[MRG] merge with lp:openobject-addons
bzr revid: tpa@tinyerp.com-20130627091956-jy98zroy5glymjm9
This commit is contained in:
commit
3cdec3adc6
|
@ -189,44 +189,34 @@ class res_partner(osv.osv):
|
|||
'debit': fields.function(_credit_debit_get, fnct_search=_debit_search, string='Total Payable', multi='dc', help="Total amount you have to pay to this supplier."),
|
||||
'debit_limit': fields.float('Payable Limit'),
|
||||
'property_account_payable': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Account Payable",
|
||||
view_load=True,
|
||||
domain="[('type', '=', 'payable')]",
|
||||
help="This account will be used instead of the default one as the payable account for the current partner",
|
||||
required=True),
|
||||
'property_account_receivable': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Account Receivable",
|
||||
view_load=True,
|
||||
domain="[('type', '=', 'receivable')]",
|
||||
help="This account will be used instead of the default one as the receivable account for the current partner",
|
||||
required=True),
|
||||
'property_account_position': fields.property(
|
||||
'account.fiscal.position',
|
||||
type='many2one',
|
||||
relation='account.fiscal.position',
|
||||
string="Fiscal Position",
|
||||
view_load=True,
|
||||
help="The fiscal position will determine taxes and accounts used for the partner.",
|
||||
),
|
||||
'property_payment_term': fields.property(
|
||||
'account.payment.term',
|
||||
type='many2one',
|
||||
relation='account.payment.term',
|
||||
string ='Customer Payment Term',
|
||||
view_load=True,
|
||||
help="This payment term will be used instead of the default one for sale orders and customer invoices"),
|
||||
'property_supplier_payment_term': fields.property(
|
||||
'account.payment.term',
|
||||
type='many2one',
|
||||
relation='account.payment.term',
|
||||
string ='Supplier Payment Term',
|
||||
view_load=True,
|
||||
help="This payment term will be used instead of the default one for purchase orders and supplier invoices"),
|
||||
'ref_companies': fields.one2many('res.company', 'partner_id',
|
||||
'Companies that refers to partner'),
|
||||
|
|
|
@ -25,18 +25,14 @@ class product_category(osv.osv):
|
|||
_inherit = "product.category"
|
||||
_columns = {
|
||||
'property_account_income_categ': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Income Account",
|
||||
view_load=True,
|
||||
help="This account will be used for invoices to value sales."),
|
||||
'property_account_expense_categ': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Expense Account",
|
||||
view_load=True,
|
||||
help="This account will be used for invoices to value expenses."),
|
||||
}
|
||||
|
||||
|
@ -54,18 +50,14 @@ class product_template(osv.osv):
|
|||
'product_supplier_taxes_rel', 'prod_id', 'tax_id',
|
||||
'Supplier Taxes', domain=[('parent_id', '=', False),('type_tax_use','in',['purchase','all'])]),
|
||||
'property_account_income': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Income Account",
|
||||
view_load=True,
|
||||
help="This account will be used for invoices instead of the default one to value sales for the current product."),
|
||||
'property_account_expense': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Expense Account",
|
||||
view_load=True,
|
||||
help="This account will be used for invoices instead of the default one to value expenses for the current product."),
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ account.""",
|
|||
'category': 'Accounting & Finance',
|
||||
'demo': [],
|
||||
'data': ['product_view.xml'],
|
||||
'test': ['test/anglo_saxon.yml'],
|
||||
'test': ['test/anglo_saxon.yml', 'test/anglo_saxon_avg_fifo.yml'],
|
||||
'auto_install': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
|
|
@ -117,21 +117,27 @@ class account_invoice_line(osv.osv):
|
|||
for line in res:
|
||||
if a == line['account_id'] and i_line.product_id.id == line['product_id']:
|
||||
uom = i_line.product_id.uos_id or i_line.product_id.uom_id
|
||||
standard_price = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.standard_price, i_line.uos_id.id)
|
||||
if standard_price != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
|
||||
price_diff = i_line.price_unit - standard_price
|
||||
line.update({'price':standard_price * line['quantity']})
|
||||
valuation_price_unit = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.standard_price, i_line.uos_id.id)
|
||||
if i_line.product_id.cost_method != 'standard' and i_line.purchase_line_id:
|
||||
#for average/fifo/lifo costing method, fetch real cost price from incomming moves
|
||||
stock_move_obj = self.pool.get('stock.move')
|
||||
valuation_stock_move = stock_move_obj.search(cr, uid, [('purchase_line_id', '=', i_line.purchase_line_id.id)], limit=1, context=context)
|
||||
if valuation_stock_move:
|
||||
valuation_price_unit = stock_move_obj.browse(cr, uid, valuation_stock_move[0], context=context).price_unit
|
||||
if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
|
||||
price_diff = i_line.price_unit - valuation_price_unit
|
||||
line.update({'price': valuation_price_unit * line['quantity']})
|
||||
diff_res.append({
|
||||
'type':'src',
|
||||
'type': 'src',
|
||||
'name': i_line.name[:64],
|
||||
'price_unit':price_diff,
|
||||
'quantity':line['quantity'],
|
||||
'price_unit': price_diff,
|
||||
'quantity': line['quantity'],
|
||||
'price': price_diff * line['quantity'],
|
||||
'account_id':acc,
|
||||
'product_id':line['product_id'],
|
||||
'uos_id':line['uos_id'],
|
||||
'account_analytic_id':line['account_analytic_id'],
|
||||
'taxes':line.get('taxes',[]),
|
||||
'account_id': acc,
|
||||
'product_id': line['product_id'],
|
||||
'uos_id': line['uos_id'],
|
||||
'account_analytic_id': line['account_analytic_id'],
|
||||
'taxes': line.get('taxes', []),
|
||||
})
|
||||
res += diff_res
|
||||
return res
|
||||
|
|
|
@ -24,27 +24,21 @@ class product_category(osv.osv):
|
|||
_inherit = "product.category"
|
||||
_columns = {
|
||||
'property_account_creditor_price_difference_categ': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Price Difference Account",
|
||||
view_load=True,
|
||||
help="This account will be used to value price difference between purchase price and cost price."),
|
||||
|
||||
#Redefine fields to change help text for anglo saxon methodology.
|
||||
'property_account_income_categ': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Income Account",
|
||||
view_load=True,
|
||||
help="This account will be used to value outgoing stock using sale price."),
|
||||
'property_account_expense_categ': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Expense Account",
|
||||
view_load=True,
|
||||
help="This account will be used to value outgoing stock using cost price."),
|
||||
|
||||
}
|
||||
|
@ -53,27 +47,21 @@ class product_template(osv.osv):
|
|||
_inherit = "product.template"
|
||||
_columns = {
|
||||
'property_account_creditor_price_difference': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Price Difference Account",
|
||||
view_load=True,
|
||||
help="This account will be used to value price difference between purchase price and cost price."),
|
||||
|
||||
#Redefine fields to change help text for anglo saxon methodology.
|
||||
'property_account_income': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Income Account",
|
||||
view_load=True,
|
||||
help="This account will be used to value outgoing stock using sale price."),
|
||||
'property_account_expense': fields.property(
|
||||
'account.account',
|
||||
type='many2one',
|
||||
relation='account.account',
|
||||
string="Expense Account",
|
||||
view_load=True,
|
||||
help="This account will be used to value outgoing stock using cost price."),
|
||||
|
||||
}
|
||||
|
|
|
@ -26,16 +26,15 @@ class purchase_order(osv.osv):
|
|||
_inherit = "purchase.order"
|
||||
_description = "Purchase Order"
|
||||
|
||||
def _prepare_inv_line(self, cr, uid, account_id, order_line, context=None):
|
||||
line = super(purchase_order, self)._prepare_inv_line(cr, uid, account_id, order_line, context=context)
|
||||
def _choose_account_from_po_line(self, cr, uid, order_line, context=None):
|
||||
account_id = super(purchase_order, self)._choose_account_from_po_line(cr, uid, order_line, context=context)
|
||||
if order_line.product_id and not order_line.product_id.type == 'service':
|
||||
acc_id = order_line.product_id.property_stock_account_input and order_line.product_id.property_stock_account_input.id
|
||||
if not acc_id:
|
||||
acc_id = order_line.product_id.categ_id.property_stock_account_input_categ and order_line.product_id.categ_id.property_stock_account_input_categ.id
|
||||
if acc_id:
|
||||
fpos = order_line.order_id.fiscal_position or False
|
||||
new_account_id = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, acc_id)
|
||||
line.update({'account_id': new_account_id})
|
||||
return line
|
||||
account_id = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, acc_id)
|
||||
return account_id
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
-
|
||||
!record {model: purchase.order, id: purchase_order_001}:
|
||||
partner_id: base.res_partner_3
|
||||
location_id: stock.stock_location_3
|
||||
location_id: stock.stock_location_stock
|
||||
pricelist_id: 1
|
||||
order_line:
|
||||
- product_id: product.product_product_3
|
||||
|
@ -128,12 +128,12 @@
|
|||
partial_id = self.create(cr, uid, {},context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]})
|
||||
self.do_partial(cr, uid, [partial_id])
|
||||
-
|
||||
I check the Stock Interim account (Received) is credit successfully.
|
||||
I check the Stock Interim account (Received) is credited successfully.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_stock_input, string : Stock Interim account (Received) is not credited successfully.}:
|
||||
- credit == 9
|
||||
-
|
||||
I check the Stock valuation account is debit sucessfully.
|
||||
I check the Stock valuation account is debited sucessfully.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_stock_valuation, string : Stock valuation account is not debited successfully.}:
|
||||
- debit == 9
|
||||
|
@ -192,7 +192,7 @@
|
|||
invoice_state: 2binvoiced
|
||||
move_lines:
|
||||
- company_id: base.main_company
|
||||
location_id: stock.stock_location_3
|
||||
location_id: stock.stock_location_stock
|
||||
product_id: product.product_product_3
|
||||
product_qty: 1.0
|
||||
product_uom: product.product_uom_unit
|
||||
|
|
|
@ -0,0 +1,304 @@
|
|||
-
|
||||
In order to test anglo_saxon Configure Different Accounts.
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_stock_valuation_fifo}:
|
||||
code: X3000f
|
||||
name: Stock Valuation Account- (test)
|
||||
parent_id: account.cas
|
||||
type: other
|
||||
user_type: account.data_account_type_asset
|
||||
-
|
||||
Configure Stock Interim account (Received).
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_stock_input_fifo}:
|
||||
code: X2800f
|
||||
name: Stock Interim account (Received)
|
||||
parent_id: account.cos
|
||||
type: other
|
||||
user_type: account.data_account_type_expense
|
||||
-
|
||||
Configure Stock Interim account (Delivered).
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_stock_output_fifo}:
|
||||
code: X2801f
|
||||
name: Stock Interim account (Delivered)
|
||||
parent_id: account.rev
|
||||
type: other
|
||||
user_type: account.data_account_type_income
|
||||
-
|
||||
Configure Price difference creditor Account.
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_price_difference_fifo}:
|
||||
code: X7095f
|
||||
name: Price difference creditor Account
|
||||
parent_id: account.cos
|
||||
type: other
|
||||
user_type: account.data_account_type_expense
|
||||
-
|
||||
Configure Cash Bank Account.
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_cash_fifo}:
|
||||
code: X5000f
|
||||
name: Cash/Bank Account
|
||||
parent_id: account.cash
|
||||
type: other
|
||||
user_type: account.data_account_type_asset
|
||||
-
|
||||
Configure Creditor Account Payable.
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_payable_fifo}:
|
||||
code: X440001f
|
||||
name: Creditor Account Payable
|
||||
parent_id: account.a_pay
|
||||
type: other
|
||||
user_type: account.data_account_type_payable
|
||||
-
|
||||
Configure Debtor Account Receivable.
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_receivable_fifo}:
|
||||
code: X400001f
|
||||
name: Debtor Account Receivable
|
||||
parent_id: account.a_recv
|
||||
type: other
|
||||
user_type: account.data_account_type_receivable
|
||||
-
|
||||
Configure Cost of Good sale Account.
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_cogs_fifo}:
|
||||
code: X7000f
|
||||
name: Cost of goods sale account
|
||||
parent_id: account.o_expense
|
||||
type: other
|
||||
user_type: account.data_account_type_expense
|
||||
-
|
||||
Configure Income Account.
|
||||
-
|
||||
!record {model: account.account, id: account_anglo_income_fifo}:
|
||||
code: X8000f
|
||||
name: Income Account
|
||||
parent_id: account.o_income
|
||||
type: other
|
||||
user_type: account.data_account_type_income
|
||||
-
|
||||
I configure the account receivable of supplier
|
||||
-
|
||||
!record {model: res.partner, id: base.res_partner_3}:
|
||||
property_account_payable: account_anglo_payable_fifo
|
||||
property_account_receivable: account_anglo_receivable_fifo
|
||||
-
|
||||
I configure the account receivable of Customer.
|
||||
-
|
||||
!record {model: res.partner, id: base.res_partner_13}:
|
||||
property_account_payable: account_anglo_payable_fifo
|
||||
property_account_receivable: account_anglo_receivable_fifo
|
||||
-
|
||||
I configure the product category with stock valuation account.
|
||||
-
|
||||
!record {model: product.category, id: product.product_category_4}:
|
||||
property_stock_valuation_account_id: account_anglo_stock_valuation_fifo
|
||||
-
|
||||
I create a product with required accounts, and cost method average (but same applies for fifo)
|
||||
-
|
||||
!record {model: product.product, id: product_fifo_anglo_saxon}:
|
||||
name: 'FIFO product for anglo saxon tests'
|
||||
list_price: 20.00
|
||||
standard_price: 0
|
||||
categ_id: product.product_category_4
|
||||
valuation: 'real_time'
|
||||
property_account_income: account_anglo_income_fifo
|
||||
property_account_expense: account_anglo_cogs_fifo
|
||||
property_account_creditor_price_difference: account_anglo_price_difference_fifo
|
||||
property_stock_account_input: account_anglo_stock_input_fifo
|
||||
property_stock_account_output: account_anglo_stock_output_fifo
|
||||
cost_method: 'average'
|
||||
-
|
||||
I create a draft Purchase Order.
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_001_fifo}:
|
||||
partner_id: base.res_partner_3
|
||||
location_id: stock.stock_location_stock
|
||||
pricelist_id: 1
|
||||
order_line:
|
||||
- product_id: product_fifo_anglo_saxon
|
||||
product_qty: 1
|
||||
price_unit: 9
|
||||
date_planned: '2013-08-31'
|
||||
taxes_id: []
|
||||
-
|
||||
I confirm the purchase order.
|
||||
-
|
||||
!workflow {model: purchase.order, ref: purchase_order_001_fifo, action: purchase_confirm}
|
||||
-
|
||||
Reception is ready for process so now done the reception.
|
||||
-
|
||||
!python {model: stock.partial.picking}: |
|
||||
pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_001_fifo")).picking_ids
|
||||
partial_id = self.create(cr, uid, {},context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]})
|
||||
self.do_partial(cr, uid, [partial_id])
|
||||
-
|
||||
I check the Stock Interim account (Received) is credit successfully.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_stock_input_fifo, string : Stock Interim account (Received) is not credited successfully.}:
|
||||
- credit == 9
|
||||
-
|
||||
I check the Stock valuation account is debit sucessfully.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_stock_valuation_fifo, string : Stock valuation account is not debited successfully.}:
|
||||
- debit == 9
|
||||
-
|
||||
I Validate Invoice of Purchase Order after having changed the price to 10.
|
||||
-
|
||||
!python {model: purchase.order}: |
|
||||
invoice_ids = [x.id for x in self.browse(cr, uid, ref("purchase_order_001_fifo")).invoice_ids]
|
||||
line_ids = self.pool.get('account.invoice.line').search(cr, uid, [('invoice_id', 'in', invoice_ids)])
|
||||
self.pool.get('account.invoice.line').write(cr, uid, line_ids, {'price_unit': 10})
|
||||
self.pool.get('account.invoice').signal_invoice_open(cr, uid, invoice_ids)
|
||||
-
|
||||
I check the Stock Interim account (Received) is debited sucessfully when Invoice validated.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_stock_input_fifo, string : Stock Interim account (Received) is not debited successfully.}:
|
||||
- debit == 9
|
||||
-
|
||||
I check the Price difference creditor Account is debited sucessfully when Invoice validated.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_price_difference_fifo, string : Price difference creditor Account is not debited successfully.}:
|
||||
- debit == 1
|
||||
-
|
||||
I check Payable(creditor) Account is Credited sucessfully when Invoice validated.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_payable_fifo, string : Payable(creditor) Account is not Credited successfully.}:
|
||||
- credit == 10
|
||||
-
|
||||
I pay the invoice.
|
||||
-
|
||||
!python {model: purchase.order}: |
|
||||
invoice_ids = self.browse(cr, uid, ref("purchase_order_001_fifo")).invoice_ids
|
||||
order = self.browse(cr, uid, ref("purchase_order_001_fifo"))
|
||||
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'cash'), ('company_id', '=', order.company_id.id)], limit=1)
|
||||
for invoice in invoice_ids:
|
||||
invoice.pay_and_reconcile(invoice.amount_total, ref('account_anglo_cash_fifo'), ref('account.period_8'), journal_ids[0], ref('account_anglo_cash_fifo'), ref('account.period_8'), journal_ids[0], name='test')
|
||||
-
|
||||
I check Payable(Creditors) Account is Debited sucessfully after invoice paid.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_payable_fifo, string : Payable(Creditors) Account is not Debited successfully.}:
|
||||
- debit == 10
|
||||
-
|
||||
I check Bank/Cash account is credited sucessfully after invoice paid.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_cash_fifo, string: Bank/Cash account is not credited successfully.}:
|
||||
- credit == 10
|
||||
-
|
||||
I create an Outgoing Picking order
|
||||
-
|
||||
!record {model: stock.picking, id: stock_picking_out001_fifo}:
|
||||
partner_id: base.res_partner_13
|
||||
invoice_state: 2binvoiced
|
||||
move_lines:
|
||||
- company_id: base.main_company
|
||||
location_id: stock.stock_location_stock
|
||||
product_id: product_fifo_anglo_saxon
|
||||
product_qty: 1.0
|
||||
location_dest_id: stock.stock_location_customers
|
||||
move_type: direct
|
||||
type: out
|
||||
-
|
||||
I need to check the availability of the product, So I make my picking order for processing later.
|
||||
-
|
||||
!python {model: stock.picking}: |
|
||||
self.draft_force_assign(cr, uid, [ref("stock_picking_out001_fifo")], {"lang": "en_US", "search_default_available":
|
||||
1, "tz": False, "active_model": "ir.ui.menu", "contact_display": "partner",
|
||||
"active_ids": [ref("stock.menu_action_picking_tree")], "active_id": ref("stock.menu_action_picking_tree"),
|
||||
})
|
||||
-
|
||||
I check the product availability, Product is available in the stock and ready to be sent.
|
||||
-
|
||||
!python {model: stock.picking}: |
|
||||
self.action_assign(cr, uid, [ref("stock_picking_out001_fifo")], {"lang": "en_US", "search_default_available":
|
||||
1, "tz": False, "active_model": "ir.ui.menu", "contact_display": "partner",
|
||||
"active_ids": [ref("stock.menu_action_picking_tree")], "active_id": ref("stock.menu_action_picking_tree"),
|
||||
})
|
||||
-
|
||||
I process the delivery.
|
||||
-
|
||||
!python {model: stock.partial.picking}: |
|
||||
partial_id = self.create(cr, uid, {}, context={'active_model':'stock.picking','active_ids':[ref('stock_picking_out001_fifo')]})
|
||||
self.do_partial(cr, uid, [partial_id])
|
||||
-
|
||||
I check Stock Interim account (Delivery) is debited successfully.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_stock_output_fifo, string : Stock Interim account (Delivery) is not debited successfully.}:
|
||||
- debit == 9
|
||||
-
|
||||
I check the Stock valuation account is credited sucessfully.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_stock_valuation_fifo, string : Stock valuation account is not credited successfully.}:
|
||||
- credit == 9
|
||||
-
|
||||
As the Invoice state of the picking order is To be invoiced. I create invoice for my outgoing picking order.
|
||||
-
|
||||
!python {model: stock.invoice.onshipping}: |
|
||||
wiz_id = self.create(cr, uid, {'invoice_date': '2013-03-04', 'journal_id': ref('account.sales_journal')},
|
||||
{'active_ids': [ref("stock_picking_out001_fifo")], "active_model": "stock.picking"})
|
||||
self.create_invoice(cr, uid, [wiz_id], {"lang": "en_US",
|
||||
"search_default_available": 1, "tz": False, "active_model": "stock.picking",
|
||||
"contact_display": "partner", "active_ids": [ref("stock_picking_out001_fifo")], "active_id": ref("stock_picking_out001_fifo")})
|
||||
-
|
||||
I check that the customer invoice is created successfully.
|
||||
-
|
||||
!python {model: account.invoice}: |
|
||||
partner_id = self.pool.get('stock.picking').browse(cr, uid, ref('stock_picking_out001_fifo')).partner_id.id
|
||||
inv_ids = self.search(cr, uid, [('type','=','out_invoice'),('partner_id','=',partner_id)])
|
||||
assert inv_ids, 'No Invoice is generated!'
|
||||
-
|
||||
I open the Invoice.
|
||||
-
|
||||
!python {model: stock.picking}: |
|
||||
move_name = self.pool.get('stock.picking').browse(cr, uid, ref('stock_picking_out001_fifo')).name
|
||||
account_invoice = self.pool.get('account.invoice').search(cr, uid, [('origin', '=', move_name)])
|
||||
account_invoice_line = self.pool.get('account.invoice.line').search(cr, uid, [('invoice_id', 'in', account_invoice)])
|
||||
self.pool.get('account.invoice.line').write(cr, uid, account_invoice_line, {'invoice_line_tax_id': [(6, 0, [])]})
|
||||
self.pool.get('account.invoice').button_reset_taxes(cr, uid, account_invoice)
|
||||
self.pool.get('account.invoice').signal_invoice_open(cr, uid, account_invoice)
|
||||
-
|
||||
I check Income Account is Credited sucessfully when Invoice validated.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_income_fifo, string : Income Account is not Credited successfully.}:
|
||||
- credit == 20
|
||||
-
|
||||
I check Cost of goods sold account for debit.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_cogs_fifo, string : Cost of goods sale is not Debited successfully.}:
|
||||
- debit == 9
|
||||
-
|
||||
I check Stock Interim account (Delivery)
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_stock_output_fifo, string : Stock Interim account (Delivery) is not credited successfully.}:
|
||||
- credit == 9
|
||||
-
|
||||
I check Receivable(Debtor) Account for debit.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_receivable_fifo, string : Receivable(Debtors) Account is not Debited successfully.}:
|
||||
- debit == 20
|
||||
-
|
||||
I pay the invoice.
|
||||
-
|
||||
!python {model: account.invoice}: |
|
||||
move_name = self.pool.get('stock.picking').browse(cr, uid, ref('stock_picking_out001_fifo')).name
|
||||
account_invoice= self.pool.get('account.invoice').search(cr, uid, [('origin', '=', move_name)])
|
||||
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'cash')], limit=1)
|
||||
pay = self.pay_and_reconcile(cr, uid, account_invoice,
|
||||
20.0, ref('account_anglo_cash_fifo'), ref('account.period_8'),
|
||||
journal_ids[0], ref('account_anglo_cash_fifo'),
|
||||
ref('account.period_8'), journal_ids[0],
|
||||
name='Payment for test customer invoice')
|
||||
assert (pay == True), "Incorrect Payment."
|
||||
-
|
||||
I check Receivable(Debtor) Account for credit.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_receivable_fifo, string : Receivable(Debtors) Account is not Credited successfully.}:
|
||||
- credit == 20
|
||||
-
|
||||
I check Bank/Cash account is debited sucessfully after invoice paid.
|
||||
-
|
||||
!assert {model: account.account, id : account_anglo_cash_fifo, string: Bank/Cash account is not successfully credited.}:
|
||||
- debit == 20
|
|
@ -7,7 +7,8 @@ from werkzeug.exceptions import BadRequest
|
|||
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
import openerp.addons.web.http as oeweb
|
||||
import openerp.addons.web.http as http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.web.controllers.main import db_monodb, set_cookie_and_redirect, login_and_redirect
|
||||
from openerp.modules.registry import RegistryManager
|
||||
|
||||
|
@ -18,7 +19,7 @@ _logger = logging.getLogger(__name__)
|
|||
#----------------------------------------------------------
|
||||
def fragment_to_query_string(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, req, **kw):
|
||||
def wrapper(self, **kw):
|
||||
if not kw:
|
||||
return """<html><head><script>
|
||||
var l = window.location;
|
||||
|
@ -30,18 +31,17 @@ def fragment_to_query_string(func):
|
|||
}
|
||||
window.location = r;
|
||||
</script></head><body></body></html>"""
|
||||
return func(self, req, **kw)
|
||||
return func(self, **kw)
|
||||
return wrapper
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Controller
|
||||
#----------------------------------------------------------
|
||||
class OAuthController(oeweb.Controller):
|
||||
_cp_path = '/auth_oauth'
|
||||
class OAuthController(http.Controller):
|
||||
|
||||
@oeweb.jsonrequest
|
||||
def list_providers(self, req, dbname):
|
||||
@http.route('/auth_oauth/list_providers', type='json', auth='none')
|
||||
def list_providers(self, dbname):
|
||||
try:
|
||||
registry = RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
|
@ -51,9 +51,9 @@ class OAuthController(oeweb.Controller):
|
|||
l = []
|
||||
return l
|
||||
|
||||
@oeweb.httprequest
|
||||
@http.route('/auth_oauth/signin', type='http', auth='none')
|
||||
@fragment_to_query_string
|
||||
def signin(self, req, **kw):
|
||||
def signin(self, **kw):
|
||||
state = simplejson.loads(kw['state'])
|
||||
dbname = state['d']
|
||||
provider = state['p']
|
||||
|
@ -71,7 +71,7 @@ class OAuthController(oeweb.Controller):
|
|||
url = '/#action=%s' % action
|
||||
elif menu:
|
||||
url = '/#menu_id=%s' % menu
|
||||
return login_and_redirect(req, *credentials, redirect_url=url)
|
||||
return login_and_redirect(*credentials, redirect_url=url)
|
||||
except AttributeError:
|
||||
# auth_signup is not installed
|
||||
_logger.error("auth_signup not installed on database %s: oauth sign up cancelled." % (dbname,))
|
||||
|
@ -88,14 +88,14 @@ class OAuthController(oeweb.Controller):
|
|||
_logger.exception("OAuth2: %s" % str(e))
|
||||
url = "/#action=login&oauth_error=2"
|
||||
|
||||
return set_cookie_and_redirect(req, url)
|
||||
return set_cookie_and_redirect(url)
|
||||
|
||||
@oeweb.httprequest
|
||||
def oea(self, req, **kw):
|
||||
@http.route('/auth_oauth/oea', type='http', auth='none')
|
||||
def oea(self, **kw):
|
||||
"""login user via OpenERP Account provider"""
|
||||
dbname = kw.pop('db', None)
|
||||
if not dbname:
|
||||
dbname = db_monodb(req)
|
||||
dbname = db_monodb()
|
||||
if not dbname:
|
||||
return BadRequest()
|
||||
|
||||
|
@ -105,7 +105,7 @@ class OAuthController(oeweb.Controller):
|
|||
try:
|
||||
model, provider_id = IMD.get_object_reference(cr, SUPERUSER_ID, 'auth_oauth', 'provider_openerp')
|
||||
except ValueError:
|
||||
return set_cookie_and_redirect(req, '/?db=%s' % dbname)
|
||||
return set_cookie_and_redirect('/?db=%s' % dbname)
|
||||
assert model == 'auth.oauth.provider'
|
||||
|
||||
state = {
|
||||
|
@ -115,6 +115,6 @@ class OAuthController(oeweb.Controller):
|
|||
}
|
||||
|
||||
kw['state'] = simplejson.dumps(state)
|
||||
return self.signin(req, **kw)
|
||||
return self.signin(**kw)
|
||||
|
||||
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -38,6 +38,8 @@ import openerp
|
|||
from openerp import SUPERUSER_ID
|
||||
from openerp.modules.registry import RegistryManager
|
||||
from openerp.addons.web.controllers.main import login_and_redirect, set_cookie_and_redirect
|
||||
import openerp.addons.web.http as http
|
||||
from openerp.addons.web.http import request
|
||||
|
||||
from .. import utils
|
||||
|
||||
|
@ -88,20 +90,19 @@ class GoogleAppsAwareConsumer(consumer.GenericConsumer):
|
|||
return super(GoogleAppsAwareConsumer, self).complete(message, endpoint, return_to)
|
||||
|
||||
|
||||
class OpenIDController(openerp.addons.web.http.Controller):
|
||||
_cp_path = '/auth_openid/login'
|
||||
class OpenIDController(http.Controller):
|
||||
|
||||
_store = filestore.FileOpenIDStore(_storedir)
|
||||
|
||||
_REQUIRED_ATTRIBUTES = ['email']
|
||||
_OPTIONAL_ATTRIBUTES = 'nickname fullname postcode country language timezone'.split()
|
||||
|
||||
def _add_extensions(self, request):
|
||||
"""Add extensions to the request"""
|
||||
def _add_extensions(self, oidrequest):
|
||||
"""Add extensions to the oidrequest"""
|
||||
|
||||
sreg_request = sreg.SRegRequest(required=self._REQUIRED_ATTRIBUTES,
|
||||
optional=self._OPTIONAL_ATTRIBUTES)
|
||||
request.addExtension(sreg_request)
|
||||
oidrequest.addExtension(sreg_request)
|
||||
|
||||
ax_request = ax.FetchRequest()
|
||||
for alias in self._REQUIRED_ATTRIBUTES:
|
||||
|
@ -111,7 +112,7 @@ class OpenIDController(openerp.addons.web.http.Controller):
|
|||
uri = utils.SREG2AX[alias]
|
||||
ax_request.add(ax.AttrInfo(uri, required=False, alias=alias))
|
||||
|
||||
request.addExtension(ax_request)
|
||||
oidrequest.addExtension(ax_request)
|
||||
|
||||
def _get_attributes_from_success_response(self, success_response):
|
||||
attrs = {}
|
||||
|
@ -133,58 +134,58 @@ class OpenIDController(openerp.addons.web.http.Controller):
|
|||
attrs[attr] = value
|
||||
return attrs
|
||||
|
||||
def _get_realm(self, req):
|
||||
return req.httprequest.host_url
|
||||
def _get_realm(self):
|
||||
return request.httprequest.host_url
|
||||
|
||||
@openerp.addons.web.http.httprequest
|
||||
def verify_direct(self, req, db, url):
|
||||
result = self._verify(req, db, url)
|
||||
@http.route('/auth_openid/login/verify_direct', type='http', auth='none')
|
||||
def verify_direct(self, db, url):
|
||||
result = self._verify(db, url)
|
||||
if 'error' in result:
|
||||
return werkzeug.exceptions.BadRequest(result['error'])
|
||||
if result['action'] == 'redirect':
|
||||
return werkzeug.utils.redirect(result['value'])
|
||||
return result['value']
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def verify(self, req, db, url):
|
||||
return self._verify(req, db, url)
|
||||
@http.route('/auth_openid/login/verify', type='json', auth='none')
|
||||
def verify(self, db, url):
|
||||
return self._verify(db, url)
|
||||
|
||||
def _verify(self, req, db, url):
|
||||
redirect_to = werkzeug.urls.Href(req.httprequest.host_url + 'auth_openid/login/process')(session_id=req.session_id)
|
||||
realm = self._get_realm(req)
|
||||
def _verify(self, db, url):
|
||||
redirect_to = werkzeug.urls.Href(request.httprequest.host_url + 'auth_openid/login/process')(session_id=request.session_id)
|
||||
realm = self._get_realm()
|
||||
|
||||
session = dict(dbname=db, openid_url=url) # TODO add origin page ?
|
||||
oidconsumer = consumer.Consumer(session, self._store)
|
||||
|
||||
try:
|
||||
request = oidconsumer.begin(url)
|
||||
oidrequest = oidconsumer.begin(url)
|
||||
except consumer.DiscoveryFailure, exc:
|
||||
fetch_error_string = 'Error in discovery: %s' % (str(exc[0]),)
|
||||
return {'error': fetch_error_string, 'title': 'OpenID Error'}
|
||||
|
||||
if request is None:
|
||||
if oidrequest is None:
|
||||
return {'error': 'No OpenID services found', 'title': 'OpenID Error'}
|
||||
|
||||
req.session.openid_session = session
|
||||
self._add_extensions(request)
|
||||
request.session.openid_session = session
|
||||
self._add_extensions(oidrequest)
|
||||
|
||||
if request.shouldSendRedirect():
|
||||
redirect_url = request.redirectURL(realm, redirect_to)
|
||||
return {'action': 'redirect', 'value': redirect_url, 'session_id': req.session_id}
|
||||
if oidrequest.shouldSendRedirect():
|
||||
redirect_url = oidrequest.redirectURL(realm, redirect_to)
|
||||
return {'action': 'redirect', 'value': redirect_url, 'session_id': request.session_id}
|
||||
else:
|
||||
form_html = request.htmlMarkup(realm, redirect_to)
|
||||
return {'action': 'post', 'value': form_html, 'session_id': req.session_id}
|
||||
form_html = oidrequest.htmlMarkup(realm, redirect_to)
|
||||
return {'action': 'post', 'value': form_html, 'session_id': request.session_id}
|
||||
|
||||
@openerp.addons.web.http.httprequest
|
||||
def process(self, req, **kw):
|
||||
session = getattr(req.session, 'openid_session', None)
|
||||
@http.route('/auth_openid/login/process', type='http', auth='none')
|
||||
def process(self, **kw):
|
||||
session = getattr(request.session, 'openid_session', None)
|
||||
if not session:
|
||||
return set_cookie_and_redirect(req, '/')
|
||||
return set_cookie_and_redirect('/')
|
||||
|
||||
oidconsumer = consumer.Consumer(session, self._store, consumer_class=GoogleAppsAwareConsumer)
|
||||
|
||||
query = req.httprequest.args
|
||||
info = oidconsumer.complete(query, req.httprequest.base_url)
|
||||
query = request.httprequest.args
|
||||
info = oidconsumer.complete(query, request.httprequest.base_url)
|
||||
display_identifier = info.getDisplayIdentifier()
|
||||
|
||||
session['status'] = info.status
|
||||
|
@ -225,7 +226,7 @@ class OpenIDController(openerp.addons.web.http.Controller):
|
|||
# TODO fill empty fields with the ones from sreg/ax
|
||||
cr.commit()
|
||||
|
||||
return login_and_redirect(req, dbname, login, key)
|
||||
return login_and_redirect(dbname, login, key)
|
||||
|
||||
session['message'] = 'This OpenID identifier is not associated to any active users'
|
||||
|
||||
|
@ -241,11 +242,11 @@ class OpenIDController(openerp.addons.web.http.Controller):
|
|||
# information in a log.
|
||||
session['message'] = 'Verification failed.'
|
||||
|
||||
return set_cookie_and_redirect(req, '/#action=login&loginerror=1')
|
||||
return set_cookie_and_redirect('/#action=login&loginerror=1')
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def status(self, req):
|
||||
session = getattr(req.session, 'openid_session', {})
|
||||
@http.route('/auth_openid/login/status', type='json', auth='none')
|
||||
def status(self):
|
||||
session = getattr(request.session, 'openid_session', {})
|
||||
return {'status': session.get('status'), 'message': session.get('message')}
|
||||
|
||||
|
||||
|
|
|
@ -23,14 +23,15 @@ import logging
|
|||
import openerp
|
||||
from openerp.modules.registry import RegistryManager
|
||||
from ..res_users import SignupError
|
||||
import openerp.addons.web.http as http
|
||||
from openerp.addons.web.http import request
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class Controller(openerp.addons.web.http.Controller):
|
||||
_cp_path = '/auth_signup'
|
||||
class Controller(http.Controller):
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def get_config(self, req, dbname):
|
||||
@http.route('/auth_signup/get_config', type='json', auth="none")
|
||||
def get_config(self, dbname):
|
||||
""" retrieve the module config (which features are enabled) for the login page """
|
||||
registry = RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
|
@ -41,8 +42,8 @@ class Controller(openerp.addons.web.http.Controller):
|
|||
}
|
||||
return config
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def retrieve(self, req, dbname, token):
|
||||
@http.route('/auth_signup/retrieve', type='json', auth="user")
|
||||
def retrieve(self, dbname, token):
|
||||
""" retrieve the user info (name, login or email) corresponding to a signup token """
|
||||
registry = RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
|
@ -50,23 +51,23 @@ class Controller(openerp.addons.web.http.Controller):
|
|||
user_info = res_partner.signup_retrieve_info(cr, openerp.SUPERUSER_ID, token)
|
||||
return user_info
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def signup(self, req, dbname, token, **values):
|
||||
@http.route('/auth_signup/signup', type='json', auth="user")
|
||||
def signup(self, dbname, token, **values):
|
||||
""" sign up a user (new or existing)"""
|
||||
try:
|
||||
self._signup_with_values(req, dbname, token, values)
|
||||
self._signup_with_values(dbname, token, values)
|
||||
except SignupError, e:
|
||||
return {'error': openerp.tools.exception_to_unicode(e)}
|
||||
return {}
|
||||
|
||||
def _signup_with_values(self, req, dbname, token, values):
|
||||
def _signup_with_values(self, dbname, token, values):
|
||||
registry = RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
res_users = registry.get('res.users')
|
||||
res_users.signup(cr, openerp.SUPERUSER_ID, values, token)
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def reset_password(self, req, dbname, login):
|
||||
@http.route('/auth_signup/reset_password', type='json', auth="user")
|
||||
def reset_password(self, dbname, login):
|
||||
""" retrieve user, and perform reset password """
|
||||
registry = RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
# Thai translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-06-20 13:54+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Thai <th@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-21 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:res.company:0
|
||||
msgid "Comments for Translator"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:ir.translation,job_id:0
|
||||
msgid "Gengo Job ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: code:addons/base_gengo/wizard/base_gengo_translations.py:114
|
||||
#, python-format
|
||||
msgid "This language is not supported by the Gengo translation services."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:res.company,gengo_comment:0
|
||||
msgid "Comments"
|
||||
msgstr "ความคิดเห็น"
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:res.company,gengo_private_key:0
|
||||
msgid "Gengo Private Key"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: model:ir.model,name:base_gengo.model_base_gengo_translations
|
||||
msgid "base.gengo.translations"
|
||||
msgstr "base.gengo.translations"
|
||||
|
||||
#. module: base_gengo
|
||||
#: help:res.company,gengo_auto_approve:0
|
||||
msgid "Jobs are Automatically Approved by Gengo."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:base.gengo.translations,lang_id:0
|
||||
msgid "Language"
|
||||
msgstr "ภาษา"
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:ir.translation,gengo_comment:0
|
||||
msgid "Comments & Activity Linked to Gengo"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: code:addons/base_gengo/wizard/base_gengo_translations.py:124
|
||||
#, python-format
|
||||
msgid "Gengo Sync Translation (Response)"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: code:addons/base_gengo/wizard/base_gengo_translations.py:72
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Gengo `Public Key` or `Private Key` are missing. Enter your Gengo "
|
||||
"authentication parameters under `Settings > Companies > Gengo Parameters`."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: selection:ir.translation,gengo_translation:0
|
||||
msgid "Translation By Machine"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: code:addons/base_gengo/wizard/base_gengo_translations.py:155
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%s\n"
|
||||
"\n"
|
||||
"--\n"
|
||||
" Commented on %s by %s."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:ir.translation,gengo_translation:0
|
||||
msgid "Gengo Translation Service Level"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: constraint:ir.translation:0
|
||||
msgid ""
|
||||
"The Gengo translation service selected is not supported for this language."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: selection:ir.translation,gengo_translation:0
|
||||
msgid "Standard"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: help:ir.translation,gengo_translation:0
|
||||
msgid ""
|
||||
"You can select here the service level you want for an automatic translation "
|
||||
"using Gengo."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:base.gengo.translations,restart_send_job:0
|
||||
msgid "Restart Sending Job"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:ir.translation:0
|
||||
msgid "To Approve In Gengo"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:res.company:0
|
||||
msgid "Private Key"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:res.company:0
|
||||
msgid "Public Key"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:res.company,gengo_public_key:0
|
||||
msgid "Gengo Public Key"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: code:addons/base_gengo/wizard/base_gengo_translations.py:123
|
||||
#, python-format
|
||||
msgid "Gengo Sync Translation (Request)"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:ir.translation:0
|
||||
msgid "Translations"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: field:res.company,gengo_auto_approve:0
|
||||
msgid "Auto Approve Translation ?"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: model:ir.actions.act_window,name:base_gengo.action_wizard_base_gengo_translations
|
||||
#: model:ir.ui.menu,name:base_gengo.menu_action_wizard_base_gengo_translations
|
||||
msgid "Gengo: Manual Request of Translation"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: code:addons/base_gengo/ir_translation.py:62
|
||||
#: code:addons/base_gengo/wizard/base_gengo_translations.py:109
|
||||
#, python-format
|
||||
msgid "Gengo Authentication Error"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: model:ir.model,name:base_gengo.model_res_company
|
||||
msgid "Companies"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:ir.translation:0
|
||||
msgid ""
|
||||
"Note: If the translation state is 'In Progress', it means that the "
|
||||
"translation has to be approved to be uploaded in this system. You are "
|
||||
"supposed to do that directly by using your Gengo Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: code:addons/base_gengo/wizard/base_gengo_translations.py:82
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Gengo connection failed with this message:\n"
|
||||
"``%s``"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:res.company:0
|
||||
msgid "Gengo Parameters"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:base.gengo.translations:0
|
||||
msgid "Send"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: selection:ir.translation,gengo_translation:0
|
||||
msgid "Ultra"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: model:ir.model,name:base_gengo.model_ir_translation
|
||||
msgid "ir.translation"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:ir.translation:0
|
||||
msgid "Gengo Translation Service"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: selection:ir.translation,gengo_translation:0
|
||||
msgid "Pro"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:base.gengo.translations:0
|
||||
msgid "Gengo Request Form"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: code:addons/base_gengo/wizard/base_gengo_translations.py:114
|
||||
#, python-format
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: help:res.company,gengo_comment:0
|
||||
msgid ""
|
||||
"This comment will be automatically be enclosed in each an every request sent "
|
||||
"to Gengo"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:base.gengo.translations:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_gengo
|
||||
#: view:base.gengo.translations:0
|
||||
msgid "or"
|
||||
msgstr ""
|
|
@ -222,17 +222,13 @@ class crm_case_section(osv.osv):
|
|||
return res
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
mail_alias = self.pool.get('mail.alias')
|
||||
if not vals.get('alias_id'):
|
||||
alias_name = vals.pop('alias_name', None) or vals.get('name') # prevent errors during copy()
|
||||
alias_id = mail_alias.create_unique_alias(cr, uid,
|
||||
{'alias_name': alias_name},
|
||||
model_name="crm.lead",
|
||||
context=context)
|
||||
vals['alias_id'] = alias_id
|
||||
res = super(crm_case_section, self).create(cr, uid, vals, context)
|
||||
mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'section_id': res, 'type': 'lead'}}, context)
|
||||
return res
|
||||
if context is None:
|
||||
context = {}
|
||||
create_context = dict(context, alias_model_name='crm.lead', alias_parent_model_name=self._name)
|
||||
section_id = super(crm_case_section, self).create(cr, uid, vals, context=create_context)
|
||||
section = self.browse(cr, uid, section_id, context=context)
|
||||
self.pool.get('mail.alias').write(cr, uid, [section.alias_id.id], {'alias_parent_thread_id': section_id, 'alias_defaults': {'section_id': section_id, 'type': 'lead'}}, context=context)
|
||||
return section_id
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
# Cascade-delete mail aliases as well, as they should not exist without the sales team.
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
<div class="oe_kanban_content">
|
||||
<h4 class="oe_center"><field name="name"/></h4>
|
||||
<div class="oe_kanban_alias oe_center" t-if="record.use_leads.raw_value and record.alias_id.value">
|
||||
<small><span class="oe_e" style="float: none;">%%</span><t t-raw="record.alias_id.raw_value[1]"/></small>
|
||||
<small><span class="oe_e oe_e_alias" style="float: none;">%%</span><t t-raw="record.alias_id.raw_value[1]"/></small>
|
||||
</div>
|
||||
<div class="oe_items_list">
|
||||
<div class="oe_salesteams_leads" t-if="record.use_leads.raw_value">
|
||||
|
@ -168,17 +168,6 @@
|
|||
<h1>
|
||||
<field name="name" string="Salesteam"/>
|
||||
</h1>
|
||||
<div name="group_alias"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}">
|
||||
<label for="alias_id" string="Email Alias"/>
|
||||
<field name="alias_id" class="oe_inline oe_read_only" required="0" nolabel="1"/>
|
||||
<span name="edit_alias" class="oe_edit_only">
|
||||
<field name="alias_name" class="oe_inline"
|
||||
attrs="{'required': [('use_leads', '=', True), ('alias_id', '!=', False)]}"/>
|
||||
@
|
||||
<field name="alias_domain" class="oe_inline" readonly="1"/>
|
||||
</span>
|
||||
</div>
|
||||
<div name="options_active">
|
||||
<field name="use_leads" class="oe_inline"/><label for="use_leads"/>
|
||||
</div>
|
||||
|
@ -187,12 +176,25 @@
|
|||
<group>
|
||||
<field name="user_id"/>
|
||||
<field name="code"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="parent_id"/>
|
||||
<field name="change_responsible"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
<group>
|
||||
<label for="alias_name" string="Email Alias"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
<div name="alias_def"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}">
|
||||
<field name="alias_id" class="oe_read_only oe_inline"
|
||||
string="Email Alias" required="0"/>
|
||||
<div class="oe_edit_only oe_inline" name="edit_alias" style="display: inline;" >
|
||||
<field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
|
||||
</div>
|
||||
</div>
|
||||
<field name="alias_contact" class="oe_inline"
|
||||
string="Accept Emails From"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Team Members">
|
||||
|
|
|
@ -719,7 +719,6 @@ class crm_lead(base_stage, format_address, osv.osv):
|
|||
continue
|
||||
vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context)
|
||||
self.write(cr, uid, [lead.id], vals, context=context)
|
||||
self.message_post(cr, uid, ids, body=_("Lead <b>converted into an Opportunity</b>"), subtype="crm.mt_lead_convert_to_opportunity", context=context)
|
||||
|
||||
if user_ids or section_id:
|
||||
self.allocate_salesman(cr, uid, ids, user_ids, section_id, context=context)
|
||||
|
|
|
@ -163,12 +163,6 @@
|
|||
<field name="default" eval="False"/>
|
||||
<field name="description">Opportunity created</field>
|
||||
</record>
|
||||
<record id="mt_lead_convert_to_opportunity" model="mail.message.subtype">
|
||||
<field name="name">Lead to Opportunity</field>
|
||||
<field name="res_model">crm.lead</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Lead converted into an opportunity</field>
|
||||
</record>
|
||||
<record id="mt_lead_stage" model="mail.message.subtype">
|
||||
<field name="name">Stage Changed</field>
|
||||
<field name="res_model">crm.lead</field>
|
||||
|
@ -195,13 +189,6 @@
|
|||
<field name="parent_id" eval="ref('mt_lead_create')"/>
|
||||
<field name="relation_field">section_id</field>
|
||||
</record>
|
||||
<record id="mt_salesteam_lead_opportunity" model="mail.message.subtype">
|
||||
<field name="name">Lead to Opportunity</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="res_model">crm.case.section</field>
|
||||
<field name="parent_id" eval="ref('mt_lead_convert_to_opportunity')"/>
|
||||
<field name="relation_field">section_id</field>
|
||||
</record>
|
||||
<record id="mt_salesteam_lead_stage" model="mail.message.subtype">
|
||||
<field name="name">Opportunity Stage Changed</field>
|
||||
<field name="res_model">crm.case.section</field>
|
||||
|
|
|
@ -601,7 +601,9 @@
|
|||
'default_email_to':'{$object.email or \'\'}',
|
||||
'default_use_template': True,
|
||||
'default_template_id': ref('crm.email_template_opportunity_mail'),
|
||||
}"/>
|
||||
}"
|
||||
groups="base.group_sale_salesman"
|
||||
/>
|
||||
|
||||
<!--Update of email_template defined in crm_lead_data, to add ref_ir_act_window
|
||||
allowing to have a well formed email template (context action considered as set). -->
|
||||
|
@ -617,6 +619,7 @@
|
|||
if context.get('active_model') == 'crm.lead' and context.get('active_ids'):
|
||||
self.case_cancel(cr, uid, context['active_ids'], context=context)
|
||||
</field>
|
||||
<field name="groups_id" eval="[(4,ref('base.group_sale_salesman'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="ir_mark_as_lost" model="ir.values">
|
||||
|
|
|
@ -7,14 +7,14 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 6.0dev\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
|
||||
"PO-Revision-Date: 2013-04-13 08:42+0000\n"
|
||||
"PO-Revision-Date: 2013-06-21 07:11+0000\n"
|
||||
"Last-Translator: krnkris <Unknown>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-04-14 05:12+0000\n"
|
||||
"X-Generator: Launchpad (build 16564)\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-22 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: crm
|
||||
#: view:crm.lead.report:0
|
||||
|
@ -31,7 +31,7 @@ msgstr ""
|
|||
"létrehozását a bejövő levelekből."
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:881
|
||||
#: code:addons/crm/crm_lead.py:898
|
||||
#: selection:crm.case.stage,type:0
|
||||
#: view:crm.lead:0
|
||||
#: selection:crm.lead,type:0
|
||||
|
@ -192,8 +192,8 @@ msgstr ""
|
|||
"direkt HTML formátumú ahhoz hogy beilleszthető legyen a kanban nézetekbe."
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:624
|
||||
#: code:addons/crm/crm_lead.py:744
|
||||
#: code:addons/crm/crm_lead.py:640
|
||||
#: code:addons/crm/crm_lead.py:761
|
||||
#: code:addons/crm/crm_phonecall.py:280
|
||||
#, python-format
|
||||
msgid "Warning!"
|
||||
|
@ -304,7 +304,7 @@ msgid "Prospect Partner"
|
|||
msgstr "Leendő partner"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:982
|
||||
#: code:addons/crm/crm_lead.py:1002
|
||||
#, python-format
|
||||
msgid "No Subject"
|
||||
msgstr "Nincs tárgy"
|
||||
|
@ -482,7 +482,7 @@ msgid "#Opportunities"
|
|||
msgstr "Lehetőségek száma"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:624
|
||||
#: code:addons/crm/crm_lead.py:640
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please select more than one element (lead or opportunity) from the list view."
|
||||
|
@ -782,7 +782,7 @@ msgid "Statistics Dashboard"
|
|||
msgstr "Statisztika vezérlőpult"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:861
|
||||
#: code:addons/crm/crm_lead.py:878
|
||||
#: model:crm.case.stage,name:crm.stage_lead2
|
||||
#: selection:crm.case.stage,type:0
|
||||
#: view:crm.lead:0
|
||||
|
@ -844,7 +844,7 @@ msgid "Exclusive"
|
|||
msgstr "Kizárólagos"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:584
|
||||
#: code:addons/crm/crm_lead.py:600
|
||||
#, python-format
|
||||
msgid "From %s : %s"
|
||||
msgstr "Ettől %s : %s"
|
||||
|
@ -1016,7 +1016,7 @@ msgid "Next Action"
|
|||
msgstr "Következő művelet"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:763
|
||||
#: code:addons/crm/crm_lead.py:780
|
||||
#, python-format
|
||||
msgid "<b>Partner</b> set to <em>%s</em>."
|
||||
msgstr "<b>Partner</b> beállítva mint <em>%s</em>."
|
||||
|
@ -1109,7 +1109,7 @@ msgid "Creation Date"
|
|||
msgstr "Létrehozás dátuma"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:698
|
||||
#: code:addons/crm/crm_lead.py:715
|
||||
#, python-format
|
||||
msgid "Lead <b>converted into an Opportunity</b>"
|
||||
msgstr "Tervezet <b>lehetőséggé átalakítva lehetőséggé</b>"
|
||||
|
@ -1324,7 +1324,9 @@ msgid "Days to Close"
|
|||
msgstr "Lezárásig hátralévő napok"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:1057
|
||||
#: field:crm.case.section,complete_name:0
|
||||
#, python-format
|
||||
msgid "unknown"
|
||||
msgstr "Ismeretlen"
|
||||
|
||||
|
@ -1415,7 +1417,7 @@ msgid "Lead Description"
|
|||
msgstr "Érdeklődés leírása"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:565
|
||||
#: code:addons/crm/crm_lead.py:581
|
||||
#, python-format
|
||||
msgid "Merged opportunities"
|
||||
msgstr "Lehetőségek összefésülése"
|
||||
|
@ -1989,7 +1991,7 @@ msgid "Leads"
|
|||
msgstr "Érdeklődők"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:563
|
||||
#: code:addons/crm/crm_lead.py:579
|
||||
#, python-format
|
||||
msgid "Merged leads"
|
||||
msgstr "Össztefésült érdeklődések"
|
||||
|
@ -2085,7 +2087,6 @@ msgid "Global CC"
|
|||
msgstr "Globális CC /másolat/"
|
||||
|
||||
#. module: crm
|
||||
#: view:crm.lead:0
|
||||
#: view:crm.phonecall:0
|
||||
#: model:ir.actions.act_window,name:crm.crm_case_categ_phone0
|
||||
#: model:ir.ui.menu,name:crm.menu_crm_case_phone
|
||||
|
@ -2399,7 +2400,7 @@ msgstr "Érdeklődés átalakítva egy lehetőséggé"
|
|||
#. module: crm
|
||||
#: view:crm.lead:0
|
||||
msgid "Unassigned Leads"
|
||||
msgstr "Nem iktatott rdeklődések"
|
||||
msgstr "Nem iktatott érdeklődések"
|
||||
|
||||
#. module: crm
|
||||
#: model:mail.message.subtype,description:crm.mt_lead_won
|
||||
|
@ -3100,7 +3101,7 @@ msgid "Working Hours"
|
|||
msgstr "Munkaórák"
|
||||
|
||||
#. module: crm
|
||||
#: code:addons/crm/crm_lead.py:968
|
||||
#: code:addons/crm/crm_lead.py:986
|
||||
#: view:crm.lead:0
|
||||
#: field:crm.lead2opportunity.partner,partner_id:0
|
||||
#: field:crm.lead2opportunity.partner.mass,partner_id:0
|
||||
|
|
|
@ -102,7 +102,9 @@
|
|||
res_model="crm.lead2opportunity.partner.mass" src_model="crm.lead"
|
||||
view_mode="form" target="new" view_type="form"
|
||||
context="{'mass_convert' : True}"
|
||||
view_id="view_crm_lead2opportunity_partner_mass"/>
|
||||
view_id="view_crm_lead2opportunity_partner_mass"
|
||||
groups="base.group_sale_salesman"
|
||||
/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -45,7 +45,9 @@
|
|||
multi="True"
|
||||
key2="client_action_multi" name="Merge leads/opportunities"
|
||||
res_model="crm.merge.opportunity" src_model="crm.lead"
|
||||
view_mode="form" target="new" view_type="form"/>
|
||||
view_mode="form" target="new" view_type="form"
|
||||
groups="base.group_sale_salesman"
|
||||
/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
##############################################################################
|
||||
|
||||
import crm_partner_assign
|
||||
import crm_lead
|
||||
import wizard
|
||||
import report
|
||||
|
||||
|
|
|
@ -37,17 +37,23 @@ The most appropriate partner can be assigned.
|
|||
You can also use the geolocalization without using the GPS coordinates.
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['crm', 'account'],
|
||||
'depends': ['crm', 'account', 'portal'],
|
||||
'demo': ['res_partner_demo.xml'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'res_partner_view.xml',
|
||||
'wizard/crm_forward_to_partner_view.xml',
|
||||
'wizard/crm_channel_interested_view.xml',
|
||||
'crm_lead_view.xml',
|
||||
'crm_partner_assign_data.xml',
|
||||
'crm_portal_view.xml',
|
||||
'portal_data.xml',
|
||||
'report/crm_lead_report_view.xml',
|
||||
'report/crm_partner_report_view.xml',
|
||||
],
|
||||
'js': [
|
||||
'static/src/js/next.js',
|
||||
],
|
||||
'test': ['test/partner_assign.yml'],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class crm_lead(osv.osv):
|
||||
_inherit = 'crm.lead'
|
||||
|
||||
def get_interested_action(self, cr, uid, interested, context=None):
|
||||
try:
|
||||
model, action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'crm_lead_channel_interested_act')
|
||||
except ValueError:
|
||||
raise osv.except_osv(_('Error!'), _("The CRM Channel Interested Action is missing"))
|
||||
action = self.pool[model].read(cr, uid, action_id, context=context)
|
||||
action_context = eval(action['context'])
|
||||
action_context['interested'] = interested
|
||||
action['context'] = str(action_context)
|
||||
return action
|
||||
|
||||
def case_interested(self, cr, uid, ids, context=None):
|
||||
return self.get_interested_action(cr, uid, True, context=context)
|
||||
|
||||
def case_disinterested(self, cr, uid, ids, context=None):
|
||||
return self.get_interested_action(cr, uid, False, context=context)
|
|
@ -8,27 +8,33 @@
|
|||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//notebook/page[@string='Lead']" position="after">
|
||||
<page string="Assignation">
|
||||
<page string="Assigned Partner" groups="base.group_sale_manager">
|
||||
<group name="partner_assign_group">
|
||||
<group string="Partner Assignation">
|
||||
<field name="partner_assigned_id" on_change="onchange_assign_id(partner_assigned_id)" domain="[('grade_id','<>',False)]"/>
|
||||
<label for="date_assign"/>
|
||||
<group string="Partner Assignation" col="3" colspan="1">
|
||||
<label for="partner_latitude" string="Geolocation" />
|
||||
<div class="oe_title">
|
||||
<h3>
|
||||
<span class="oe_grey">( </span>
|
||||
<field name="partner_latitude" nolabel="1" readonly="1" class="oe_inline"/>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','<=',0)]}">N </span>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','>=',0)]}">S </span>
|
||||
<field name="partner_longitude" class="oe_inline" readonly="1" nolabel="1"/>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','<=',0)]}">E </span>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','>=',0)]}">W </span>
|
||||
<span class="oe_grey">) </span>
|
||||
</h3>
|
||||
</div>
|
||||
<button string="Automatic Assignation" name="action_assign_partner" type="object" colspan="1"
|
||||
class="oe_inline"/>
|
||||
<field name="partner_assigned_id" class="oe_inline" on_change="onchange_assign_id(partner_assigned_id)" domain="[('grade_id','<>',False)]"/>
|
||||
<div>
|
||||
<field name="date_assign"/>
|
||||
<button string="Forward"
|
||||
<button string="Send Email"
|
||||
attrs="{'invisible':[('partner_assigned_id','=',False)]}"
|
||||
name="%(crm_lead_forward_to_partner_act)d"
|
||||
icon="terp-mail-forward" type="action"
|
||||
context="{'default_composition_mode': 'forward', 'default_partner_ids': [partner_assigned_id]}"/>
|
||||
type="action"
|
||||
context="{'default_composition_mode': 'forward','hide_forward_type': 1 , 'default_partner_ids': [partner_assigned_id]}"/>
|
||||
</div>
|
||||
</group>
|
||||
<group string="Geo Assignation">
|
||||
<field name="partner_latitude"/>
|
||||
<field name="partner_longitude"/>
|
||||
<span/>
|
||||
<button string="Geo Assign" name="action_assign_partner" type="object" colspan="1"
|
||||
icon="gtk-apply"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
|
@ -43,7 +49,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<field name="partner_id" position="after">
|
||||
<field name="partner_assigned_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
@ -55,41 +61,46 @@
|
|||
<filter string="Team" position="after">
|
||||
<filter string="Assigned Partner" icon="terp-personal" domain="[]" context="{'group_by':'partner_assigned_id'}"/>
|
||||
</filter>
|
||||
|
||||
<field name="partner_id" position="after">
|
||||
<field name="partner_assigned_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</record>
|
||||
|
||||
<record id="view_crm_lead_geo_assign_form" model="ir.ui.view">
|
||||
<record id="view_crm_lead_geo_assign_form" model="ir.ui.view">
|
||||
<field name="name">crm.lead.lead.geo_assign.inherit</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.crm_case_form_view_leads"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//notebook/page[@string='Extra Info']" position="after">
|
||||
<page string="Assignation">
|
||||
<page string="Assigned Partner" groups="base.group_sale_manager">
|
||||
<group name="partner_assign_group">
|
||||
<group string="Partner Assignation">
|
||||
<field name="partner_assigned_id" on_change="onchange_assign_id(partner_assigned_id)" domain="[('grade_id','<>',False)]"/>
|
||||
<label for="date_assign"/>
|
||||
<group string="Partner Assignation" col="3">
|
||||
<label for="partner_latitude" string="Geolocation" />
|
||||
<div>
|
||||
<field name="date_assign"/>
|
||||
<button string="Forward"
|
||||
<h3>
|
||||
<span class="oe_grey">( </span>
|
||||
<field name="partner_latitude" nolabel="1" readonly="1" class="oe_inline"/>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','<=',0)]}">N </span>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','>=',0)]}">S </span>
|
||||
<field name="partner_longitude" class="oe_inline" readonly="1" nolabel="1"/>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','<=',0)]}">E </span>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','>=',0)]}">W </span>
|
||||
<span class="oe_grey">) </span>
|
||||
</h3>
|
||||
</div>
|
||||
<button string="Automatic Assignation" name="action_assign_partner" type="object" colspan="1"
|
||||
class="oe_inline" />
|
||||
<field name="partner_assigned_id" class="oe_inline" on_change="onchange_assign_id(partner_assigned_id)" domain="[('grade_id','<>',False)]"/>
|
||||
<div>
|
||||
<button string="Send Email"
|
||||
attrs="{'invisible':[('partner_assigned_id','=',False)]}"
|
||||
name="%(crm_lead_forward_to_partner_act)d"
|
||||
icon="terp-mail-forward" type="action"
|
||||
context="{'default_composition_mode': 'forward', 'default_partner_ids': [partner_assigned_id]}"/>
|
||||
type="action"
|
||||
context="{'default_composition_mode': 'forward','hide_forward_type': 1 , 'default_partner_ids': [partner_assigned_id]}"/>
|
||||
</div>
|
||||
</group>
|
||||
<group string="Geo Assignation">
|
||||
<field name="partner_latitude"/>
|
||||
<field name="partner_longitude"/>
|
||||
<span/>
|
||||
<button string="Geo Assign" name="action_assign_partner" type="object" colspan="1"
|
||||
icon="gtk-apply"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
|
@ -104,7 +115,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<field name="partner_id" position="after">
|
||||
<field name="partner_assigned_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
@ -116,12 +127,11 @@
|
|||
<filter string="Team" position="after">
|
||||
<filter string="Assigned Partner" icon="terp-personal" domain="[]" context="{'group_by':'partner_assigned_id'}"/>
|
||||
</filter>
|
||||
|
||||
<field name="partner_id" position="after">
|
||||
<field name="partner_assigned_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -66,10 +66,13 @@ class res_partner_grade(osv.osv):
|
|||
_columns = {
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'active': fields.boolean('Active'),
|
||||
'name': fields.char('Grade Name', size=32)
|
||||
'name': fields.char('Grade Name', size=32),
|
||||
'partner_weight': fields.integer('Grade Weight',
|
||||
help="Gives the probability to assign a lead to this partner. (0 means no assignation.)"),
|
||||
}
|
||||
_defaults = {
|
||||
'active': lambda *args: 1
|
||||
'active': lambda *args: 1,
|
||||
'partner_weight':1
|
||||
}
|
||||
|
||||
class res_partner_activation(osv.osv):
|
||||
|
@ -88,11 +91,11 @@ class res_partner(osv.osv):
|
|||
'partner_latitude': fields.float('Geo Latitude'),
|
||||
'partner_longitude': fields.float('Geo Longitude'),
|
||||
'date_localization': fields.date('Geo Localization Date'),
|
||||
'partner_weight': fields.integer('Weight',
|
||||
'partner_weight': fields.integer('Grade Weight',
|
||||
help="Gives the probability to assign a lead to this partner. (0 means no assignation.)"),
|
||||
'opportunity_assigned_ids': fields.one2many('crm.lead', 'partner_assigned_id',\
|
||||
'Assigned Opportunities'),
|
||||
'grade_id': fields.many2one('res.partner.grade', 'Partner Level'),
|
||||
'grade_id': fields.many2one('res.partner.grade', 'Grade'),
|
||||
'activation' : fields.many2one('res.partner.activation', 'Activation', select=1),
|
||||
'date_partnership' : fields.date('Partnership Date'),
|
||||
'date_review' : fields.date('Latest Partner Review'),
|
||||
|
@ -101,6 +104,13 @@ class res_partner(osv.osv):
|
|||
_defaults = {
|
||||
'partner_weight': lambda *args: 0
|
||||
}
|
||||
|
||||
def onchange_grade_id(self, cr, uid, ids, grade_id, context=None):
|
||||
res = {'value' :{'partner_weight':0}}
|
||||
if grade_id:
|
||||
partner_grade = self.pool.get('res.partner.grade').browse(cr, uid, grade_id)
|
||||
res['value']['partner_weight'] = partner_grade.partner_weight
|
||||
return res
|
||||
def geo_localize(self, cr, uid, ids, context=None):
|
||||
# Don't pass context to browse()! We need country names in english below
|
||||
for partner in self.browse(cr, uid, ids):
|
||||
|
@ -124,7 +134,7 @@ class crm_lead(osv.osv):
|
|||
_columns = {
|
||||
'partner_latitude': fields.float('Geo Latitude'),
|
||||
'partner_longitude': fields.float('Geo Longitude'),
|
||||
'partner_assigned_id': fields.many2one('res.partner', 'Assigned Partner', help="Partner this case has been forwarded/assigned to.", select=True),
|
||||
'partner_assigned_id': fields.many2one('res.partner', 'Assigned Partner',track_visibility='onchange' , help="Partner this case has been forwarded/assigned to.", select=True),
|
||||
'date_assign': fields.date('Assignation Date', help="Last date this case was forwarded/assigned to a partner"),
|
||||
}
|
||||
def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
|
||||
|
@ -134,6 +144,7 @@ class crm_lead(osv.osv):
|
|||
def onchange_assign_id(self, cr, uid, ids, partner_assigned_id, context=None):
|
||||
"""This function updates the "assignation date" automatically, when manually assign a partner in the geo assign tab
|
||||
"""
|
||||
|
||||
if not partner_assigned_id:
|
||||
return {'value':{'date_assign': False}}
|
||||
else:
|
||||
|
@ -261,4 +272,3 @@ class crm_lead(osv.osv):
|
|||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -1,44 +1,59 @@
|
|||
<?xml version="1.0" encoding='UTF-8'?>
|
||||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="crm_partner_assign_email_template" model="email.template">
|
||||
<field name="name">Lead forward</field>
|
||||
<field name="email_from"></field>
|
||||
<field name="subject">Fwd: Lead: ${object.name}</field>
|
||||
<field name="email_to"></field>
|
||||
<field name="lang"></field>
|
||||
<field name="model_id" ref="crm.model_crm_lead"/>
|
||||
<record model="crm.case.stage" id="stage_portal_lead_assigned">
|
||||
<field name="name">Assigned</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field eval="0" name="probability"/>
|
||||
<field eval="12" name="sequence"/>
|
||||
<field name="type">lead</field>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_portal_lead_recycle">
|
||||
<field name="name">To Recycle</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field eval="0" name="probability"/>
|
||||
<field eval="11" name="sequence"/>
|
||||
<field name="type">lead</field>
|
||||
</record>
|
||||
<record id="email_template_lead_forward_mail" model="email.template">
|
||||
<field name="name">Lead Mass Mail</field>
|
||||
<field name="model_id" model="ir.model" search="[('name', '=', 'crm.lead.forward.to.partner')]"></field>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="email_to">${ctx['partner_id'].email}</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">Fwd: Lead: ${ctx['partner_id'].name}</field>
|
||||
<field name="body_html"><![CDATA[
|
||||
Hello ${object.partner_assigned_id.name},
|
||||
<p>
|
||||
Here is a lead that might interest you.
|
||||
</p>
|
||||
<p>
|
||||
Please keep me informed about your actions about it so that I can keep an
|
||||
accurate follow-up of it and help you in the sale cycle.
|
||||
</p>
|
||||
<p>
|
||||
Your account manager,<br/>
|
||||
${object.user_id.name},<br/>
|
||||
${object.user_id.email}
|
||||
</p>
|
||||
|
||||
<p>Hello,</p>
|
||||
|
||||
<p>
|
||||
${ctx["mail_body"].replace('\n','<br>') | safe}
|
||||
</p>
|
||||
|
||||
% if ctx["history_mode"] in ('whole'):
|
||||
% for message in object.message_ids:
|
||||
---- Original Message (${message.date or ''}) ----<br/>
|
||||
${message.body | safe}
|
||||
% endfor
|
||||
<p>We have been contacted by those prospects that are in your region. Thus, the following leads have been assigned to ${ctx['partner_id'].name}:</p>
|
||||
|
||||
<ol>
|
||||
% for lead in ctx['partner_leads']:
|
||||
<li><a href="${lead.lead_link}">${lead.lead_id.name or 'Subject Undefined'}</a>, ${lead.lead_id.contact_name or 'Contact Name Undefined'}, ${lead.lead_id.country_id and lead.lead_id.country_id.name or 'Country Undefined' }, ${lead.lead_id.email_from or 'Email Undefined'}, ${lead.lead_id.phone or ''} </li></br>
|
||||
% endfor
|
||||
</ol>
|
||||
|
||||
% if ctx.get('partner_in_portal'):
|
||||
<p>Please connect to your <a href="${object.get_portal_url()}">Partner Portal</a> to get details. On each lead are two buttons on the top left corner that you should press after having contacted the lead: "I'm interested" & "I'm not interested".</p>
|
||||
% else:
|
||||
<p>
|
||||
You do not have yet a portal access to our database. Please contact
|
||||
${ctx['partner_id'].user_id and ctx['partner_id'].user_id.email and 'your account manager %s (%s)' % (ctx['partner_id'].user_id.name,ctx['partner_id'].user_id.email) or 'us'}.
|
||||
</p>
|
||||
% endif
|
||||
% if ctx['history_mode'] == 'latest':
|
||||
---- Original Message (${object.message_ids[0].date or ''}) ----<br/>
|
||||
${object.message_ids[0].body | safe}
|
||||
<p>The lead will be sent to another partner if you do not contact the lead before 20 days.</p>
|
||||
|
||||
<p>Thanks,</p>
|
||||
|
||||
<pre>
|
||||
${ctx['partner_id'].user_id and ctx['partner_id'].user_id.signature or ''}
|
||||
</pre>
|
||||
% if not ctx['partner_id'].user_id:
|
||||
PS: It looks like you do not have an account manager assigned to you, please contact us.
|
||||
% endif
|
||||
]]></field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</openerp>
|
|
@ -0,0 +1,209 @@
|
|||
<openerp>
|
||||
<data>
|
||||
<!-- lead views-->
|
||||
<record model="ir.ui.view" id="crm_lead_portal_tree">
|
||||
<field name="name">partner lead</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="priority" eval="32"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Leads" colors="blue:state=='pending';grey:state in ('cancel', 'done');red:stage_id[1]=='Disinterested';black:stage_id[1]=='Interested'">
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date"/>
|
||||
<field name="name" string="Subject"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="country_id" invisible="context.get('invisible_country', True)" />
|
||||
<field name="email_from"/>
|
||||
<field name="phone"/>
|
||||
<field name="stage_id" invisible="1"/>
|
||||
<field name="type_id" invisible="1"/>
|
||||
<field name="referred" invisible="1"/>
|
||||
<field name="channel_id" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="section_id" invisible="context.get('invisible_section', True)" />
|
||||
|
||||
<button string="I'm interested" name="case_interested" icon="gtk-index" type="object"/>
|
||||
<button string="I'm not interested" name="case_disinterested" icon="gtk-close" type="object"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model= "ir.ui.view" id="crm_lead_portal_form">
|
||||
<field name="name">crm_portal_form</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="priority" eval="32"/>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Leads" version="7.0">
|
||||
<header>
|
||||
<button string="I'm interested" name="case_interested" icon="gtk-index" type="object"/>
|
||||
<button string="I'm not interested" name="case_disinterested" icon="gtk-close" type="object"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_name" string="Partner Name" readonly="1"/>
|
||||
<field name="title" widget="selection" readonly="1"/>
|
||||
<field name="contact_name" readonly="1"/>
|
||||
<field name="function" readonly="1"/>
|
||||
<field name="email_from" readonly="1"/>
|
||||
<field name="phone" readonly="1"/>
|
||||
<field name="fax" readonly="1"/>
|
||||
<field name="mobile" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="street" readonly="1"/>
|
||||
<field name="street2" readonly="1"/>
|
||||
<field name="zip" readonly="1"/>
|
||||
<field name="city" readonly="1"/>
|
||||
<field name="country_id" readonly="1"/>
|
||||
<field name="state_id" readonly="1"/>
|
||||
</group>
|
||||
<label for="description" colspan="2"/>
|
||||
<field name="description" nolabel="1" colspan="2"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<!-- opportunity views-->
|
||||
<record model="ir.ui.view" id="crm_opportunity_portal_tree">
|
||||
<field name="name">partner lead</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="priority" eval="32"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Leads" colors="blue:state=='pending';grey:state in ('cancel', 'done')">
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name" string="Opportunity"/>
|
||||
<field name="partner_id" string="Customer"/>
|
||||
<field name="country_id" invisible="context.get('invisible_country', True)" />
|
||||
<field name="date_action"/>
|
||||
<field name="title_action" />
|
||||
<field name="channel_id" invisible="1"/>
|
||||
<field name="type_id" invisible="1"/>
|
||||
<field name="planned_revenue" sum="Expected Revenues"/>
|
||||
<field name="probability" widget="progressbar" avg="Avg. of Probability"/>
|
||||
<field name="section_id" invisible="context.get('invisible_section', True)" />
|
||||
<field name="priority" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model= "ir.ui.view" id="crm_opportunity_portal_form">
|
||||
<field name="name">crm_portal_form</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="priority" eval="32"/>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Leads" version="7.0">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" required="1" string="Opportunity"/>
|
||||
<field name="planned_revenue" readonly="1"/>
|
||||
<field name="probability" readonly="1"/>
|
||||
<field name="date_deadline"/>
|
||||
<newline/>
|
||||
<field name="date_action" readonly="1"/>
|
||||
<field name="title_action" readonly="1"/>
|
||||
<field name="priority" string="Priority" readonly="1"/>
|
||||
<newline/>
|
||||
<field name="type" invisible="1" readonly="1"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Opportunity">
|
||||
<group col="2">
|
||||
<separator string="Contact" colspan="2"/>
|
||||
<group col="2">
|
||||
<field name="partner_id" select="1"
|
||||
on_change="onchange_partner_id(partner_id, email_from)" string="Customer"
|
||||
colspan="2" readonly="1"/>
|
||||
<field name="partner_name" string="Customer Name" readonly="1"/>
|
||||
<field domain="[('domain', '=', 'contact')]" name="title" widget="selection" readonly="1"/>
|
||||
<field name="function" readonly="1"/>
|
||||
<field name="street" readonly="1"/>
|
||||
<field name="street2" readonly="1"/>
|
||||
</group>
|
||||
<group col="2">
|
||||
<field name="zip" readonly="1"/>
|
||||
<field name="city" readonly="1"/>
|
||||
<field name="country_id" readonly="1"/>
|
||||
<field name="state_id" readonly="1"/>
|
||||
<field name="phone" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group col="2">
|
||||
<separator string="Communication" colspan="2"/>
|
||||
<field name="email_from" readonly="1"/>
|
||||
<field name="phone" readonly="1"/>
|
||||
<field name="fax" readonly="1"/>
|
||||
<field name="mobile" readonly="1"/>
|
||||
</group>
|
||||
<group col="2">
|
||||
<separator string="Categorization" colspan="2"/>
|
||||
<field name="type_id" widget="selection" readonly="1"/>
|
||||
<field name="channel_id" widget="selection" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="Details" />
|
||||
<field name="description" nolabel="1" colspan="4"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- leads -->
|
||||
|
||||
<record id="action_portal_leads" model="ir.actions.act_window">
|
||||
<field name="name">Leads</field>
|
||||
<field name="res_model">crm.lead</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="crm_lead_portal_tree"/>
|
||||
<field name="domain">[('type','like','lead')]</field>
|
||||
</record>
|
||||
|
||||
<record id="action_portal_lead_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="crm_lead_portal_tree"/>
|
||||
<field name="act_window_id" ref="action_portal_leads"/>
|
||||
</record>
|
||||
|
||||
<record id="action_portal_lead_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="crm_lead_portal_form"/>
|
||||
<field name="act_window_id" ref="action_portal_leads"/>
|
||||
</record>
|
||||
|
||||
<!-- opportunities -->
|
||||
|
||||
<record id="action_portal_opportunities" model="ir.actions.act_window">
|
||||
<field name="name">Opportunities</field>
|
||||
<field name="res_model">crm.lead</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="crm_opportunity_portal_tree"/>
|
||||
<field name="domain">[('type','like','opportunity')]</field>
|
||||
</record>
|
||||
|
||||
<record id="action_portal_opportunities_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="crm_opportunity_portal_tree"/>
|
||||
<field name="act_window_id" ref="action_portal_opportunities"/>
|
||||
</record>
|
||||
|
||||
<record id="action_portal_opportunities_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="crm_opportunity_portal_form"/>
|
||||
<field name="act_window_id" ref="action_portal_opportunities"/>
|
||||
</record>
|
||||
|
||||
<!--menus-->
|
||||
<menuitem name="Leads & Opportunities" id="portal_leads" parent="portal.portal_menu" sequence="25"/>
|
||||
<menuitem action="action_portal_leads" sequence="0" id="openerp_portal_menu_sales_leads_current" parent="portal_leads"/>
|
||||
<menuitem action="action_portal_opportunities" sequence="1" id="openerp_portal_menu_sales_leads_current1" parent="portal_leads"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Partner and address -->
|
||||
<record id="res_partner_access" model="ir.model.access">
|
||||
<field name="name">openerp.portal.res.partner</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="group_id" ref="portal.group_portal"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_create" eval="0"/>
|
||||
<field name="perm_write" eval="0"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
<record id="res_partner_rule" model="ir.rule">
|
||||
<field name="name">openerp.portal.res.partner</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="groups" eval="[(6,0,[ref('portal.group_portal')])]"/>
|
||||
<field name="domain_force">[('id','child_of',user.commercial_partner_id.id)]</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_access" model="ir.model.access">
|
||||
<field name="name">openerp.portal.res.partner.grade</field>
|
||||
<field name="model_id" ref="crm_partner_assign.model_res_partner_grade"/>
|
||||
<field name="group_id" ref="portal.group_portal"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_create" eval="0"/>
|
||||
<field name="perm_write" eval="0"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
<!-- CRM Lead portal -->
|
||||
<record id="assigned_lead_portal_rule_1" model="ir.rule">
|
||||
<field name="name">openerp.portal.crm.lead</field>
|
||||
<field name="model_id" ref="crm.model_crm_lead"/>
|
||||
<field name="groups" eval="[(6,0,[ref('portal.group_portal')])]"/>
|
||||
<field name="domain_force">[('partner_assigned_id','child_of',user.commercial_partner_id.id)]</field>
|
||||
</record>
|
||||
<record id="lead_portal_access" model="ir.model.access">
|
||||
<field name="name">openerp.portal.crm.lead</field>
|
||||
<field name="model_id" ref="crm.model_crm_lead"/>
|
||||
<field name="group_id" ref="portal.group_portal"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_create" eval="0"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -2,7 +2,7 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<!--Partner Activation -->
|
||||
<!--Partner Activation -->
|
||||
|
||||
<record model="ir.ui.view" id="res_partner_activation_form">
|
||||
<field name="name">openerp_custom.res.partner.activation.form</field>
|
||||
|
@ -33,145 +33,134 @@
|
|||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="res_partner_activation_config_mi" parent="base.menu_config_address_book" action="res_partner_activation_act" groups="base.group_no_one"/>
|
||||
<menuitem id="res_partner_activation_config_mi" parent="base.menu_config_address_book" action="res_partner_activation_act" groups="base.group_no_one" />
|
||||
|
||||
<!--Partner Grade -->
|
||||
<!--Partner Grade -->
|
||||
|
||||
|
||||
<record id="view_partner_grade_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.grade.tree</field>
|
||||
<field name="model">res.partner.grade</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Partner Grade">
|
||||
<field name="sequence" invisible="1"/>
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_partner_grade_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.grade.form</field>
|
||||
<field name="model">res.partner.grade</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Partner Grade" version="7.0">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="sequence"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_action" model="ir.actions.act_window">
|
||||
<field name="name">Partner Grade</field>
|
||||
<field name="res_model">res.partner.grade</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
<menuitem action="res_partner_grade_action" id="menu_res_partner_grade_action"
|
||||
groups="base.group_no_one"
|
||||
parent="base.menu_crm_config_lead" />
|
||||
|
||||
<!-- Partner form -->
|
||||
<record id="view_res_partner_filter_assign_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.geo.inherit.tree</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="user_id" position="after">
|
||||
<field name="date_review_next"/>
|
||||
<field name="grade_id"/>
|
||||
<field name="activation"/>
|
||||
<record id="view_partner_grade_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.grade.tree</field>
|
||||
<field name="model">res.partner.grade</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Partner Grade">
|
||||
<field name="sequence" invisible="1" />
|
||||
<field name="name" />
|
||||
</tree>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_res_partner_filter_assign" model="ir.ui.view">
|
||||
<field name="name">res.partner.geo.inherit.search</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_res_partner_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter string="Salesperson" position="after">
|
||||
<filter string="Activation" context="{'group_by' : 'activation'}" domain="[]" icon="terp-personal" />
|
||||
</filter>
|
||||
<field name="category_id" position="after">
|
||||
<field name="grade_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_crm_partner_geo_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.geo.inherit</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook[last()]" position="inside">
|
||||
<page string="Geo Localization">
|
||||
<group>
|
||||
</record>
|
||||
<record id="view_partner_grade_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.grade.form</field>
|
||||
<field name="model">res.partner.grade</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Partner Grade" version="7.0">
|
||||
<group col="4">
|
||||
<group>
|
||||
<separator string="Partner Activation" colspan="2"/>
|
||||
<field name="grade_id" widget="selection"/>
|
||||
<field name="activation" widget="selection"/>
|
||||
<field name="partner_weight"/>
|
||||
<field name="name" />
|
||||
<field name="partner_weight" />
|
||||
<div>
|
||||
<p class="oe_grey">
|
||||
Define a weight to this grade. The weight will be used as default in the partner form to compute the chance for this partner to get leads. For instance, for business purpose, you can define a target revenue for each grade. To give the same chance to each partner to get leads, keep 1 in this field.
|
||||
</p>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<separator string="Partner Review" colspan="2"/>
|
||||
<field name="date_review"/>
|
||||
<field name="date_review_next"/>
|
||||
<field name="date_partnership"/>
|
||||
<field name="sequence" />
|
||||
<field name="active" />
|
||||
</group>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Geo Localization" colspan="2"/>
|
||||
<button
|
||||
string="Geo Localize"
|
||||
name="geo_localize"
|
||||
colspan="2"
|
||||
icon="gtk-apply"
|
||||
type="object"/>
|
||||
<field name="partner_latitude"/>
|
||||
<field name="partner_longitude"/>
|
||||
<field name="date_localization"/>
|
||||
</group>
|
||||
<newline/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_action" model="ir.actions.act_window">
|
||||
<field name="name">Partner Grade</field>
|
||||
<field name="res_model">res.partner.grade</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
<menuitem action="res_partner_grade_action" id="menu_res_partner_grade_action" groups="base.group_no_one" parent="base.menu_crm_config_lead" />
|
||||
|
||||
<field name="opportunity_assigned_ids" colspan="4" nolabel="1">
|
||||
<tree string="Assigned Opportunities" colors="blue:state=='pending';gray:state=='cancel'">
|
||||
<field name="create_date"/>
|
||||
<field name="name"/>
|
||||
<field name="type"/>
|
||||
<field name="stage_id"/>
|
||||
<button name="stage_previous" string="Previous"
|
||||
states="open,pending" type="object" icon="gtk-go-back" />
|
||||
<button name="stage_next" string="Next"
|
||||
states="open,pending" type="object"
|
||||
icon="gtk-go-forward" />
|
||||
<field name="section_id"
|
||||
invisible="context.get('invisible_section', True)"
|
||||
groups="base.group_multi_salesteams"/>
|
||||
<field name="user_id" />
|
||||
<field name="state" />
|
||||
<button name="case_cancel" string="Cancel"
|
||||
states="draft,open,pending" type="object"
|
||||
icon="gtk-cancel" />
|
||||
<button name="case_open" string="Open"
|
||||
states="draft,pending" type="object"
|
||||
icon="gtk-go-forward" />
|
||||
<button name="case_close" string="Close"
|
||||
states="open,draft,pending" type="object"
|
||||
icon="gtk-close" />
|
||||
<button string="Convert to Opportunity"
|
||||
name="convert_opportunity"
|
||||
states="draft,open,pending" icon="gtk-index"
|
||||
type="object" attrs="{'invisible':[('type','=','opportunity')]}" />
|
||||
<button name="case_escalate" string="Escalate"
|
||||
states="open,draft,pending" type="object"
|
||||
icon="gtk-go-up" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!-- Partner form -->
|
||||
<record id="view_res_partner_filter_assign_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.geo.inherit.tree</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_tree" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="user_id" position="after">
|
||||
<field name="date_review_next" />
|
||||
<field name="grade_id" />
|
||||
<field name="activation" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_res_partner_filter_assign" model="ir.ui.view">
|
||||
<field name="name">res.partner.geo.inherit.search</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_res_partner_filter" />
|
||||
<field name="arch" type="xml">
|
||||
<filter string="Salesperson" position="after">
|
||||
<filter string="Activation" context="{'group_by' : 'activation'}" domain="[]" icon="terp-personal" />
|
||||
</filter>
|
||||
<field name="category_id" position="after">
|
||||
<field name="grade_id" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_crm_partner_geo_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.geo.inherit</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook[last()]" position="inside">
|
||||
<page string="Forwarded Leads">
|
||||
<group>
|
||||
<group string="Partner Activation">
|
||||
<label for="partner_latitude" string="Geolocalisation" />
|
||||
<div class="oe_title oe_inline">
|
||||
<h3 class="oe_inline">
|
||||
<span class="oe_grey">( </span>
|
||||
<field name="partner_latitude" nolabel="1" readonly="1" class="oe_inline" />
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','<=',0)]}">N </span>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','>=',0)]}">S </span>
|
||||
<field name="partner_longitude" class="oe_inline" readonly="1" nolabel="1" />
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','<=',0)]}">E </span>
|
||||
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','>=',0)]}">W </span>
|
||||
<span class="oe_grey">) </span>
|
||||
</h3>
|
||||
<button string="Geolocalize" name="geo_localize" class="oe_inline" type="object" />
|
||||
</div>
|
||||
<field name="grade_id" widget="selection" on_change="onchange_grade_id(grade_id)" />
|
||||
<field name="partner_weight" class="oe_inline" />
|
||||
<div colspan="2">
|
||||
<p class="oe_grey">
|
||||
Higher is the value, higher is the probability for this partner to get more leads.
|
||||
</p>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<separator string="Partner Review" colspan="2" />
|
||||
<field name="date_review" />
|
||||
<field name="date_review_next" />
|
||||
<field name="date_partnership" />
|
||||
</group>
|
||||
<group>
|
||||
</group>
|
||||
</group>
|
||||
<newline />
|
||||
<separator string="Forwarded Leads" colspan="2" />
|
||||
<field name="opportunity_assigned_ids" colspan="4" nolabel="1">
|
||||
<tree string="Assigned Opportunities" colors="blue:state=='pending';gray:state=='cancel'">
|
||||
<field name="name" />
|
||||
<field name="contact_name" />
|
||||
<field name="email_from" />
|
||||
<field name="phone" />
|
||||
<field name="stage_id" />
|
||||
<field name="state" invisible="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -5,3 +5,4 @@ access_crm_partner_report,crm.partner.report.assign.all,model_crm_partner_report
|
|||
access_res_partner_grade,res.partner.grade,model_res_partner_grade,base.group_sale_salesman,1,1,1,0
|
||||
access_res_partner_grade_manager,res.partner.grade.manager,model_res_partner_grade,base.group_sale_manager,1,1,1,1
|
||||
"access_partner_activation_manager","res.partner.activation.manager","model_res_partner_activation","base.group_partner_manager",1,1,1,1
|
||||
partner_access_crm_lead,crm.lead,model_crm_lead,portal.group_portal,1,1,0,0
|
|
|
@ -0,0 +1,13 @@
|
|||
openerp.crm_partner_assign = function (instance) {
|
||||
instance.crm_partner_assign = instance.crm_partner_assign || {};
|
||||
instance.crm_partner_assign.next_or_list = function(parent) {
|
||||
var form = parent.inner_widget.views.form.controller;
|
||||
form.dataset.remove_ids([form.dataset.ids[form.dataset.index]]);
|
||||
form.reload();
|
||||
if (!form.dataset.ids.length){
|
||||
parent.inner_widget.switch_mode('list');
|
||||
}
|
||||
parent.do_action({ type: 'ir.actions.act_window_close' });
|
||||
};
|
||||
instance.web.client_actions.add("next_or_list", "instance.crm_partner_assign.next_or_list");
|
||||
}
|
|
@ -20,3 +20,4 @@
|
|||
##############################################################################
|
||||
|
||||
import crm_forward_to_partner
|
||||
import crm_channel_interested
|
|
@ -0,0 +1,76 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
||||
# $Id$
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
|
||||
class crm_lead_forward_to_partner(osv.TransientModel):
|
||||
""" Forward info history to partners. """
|
||||
_name = 'crm.lead.channel.interested'
|
||||
_columns = {
|
||||
'interested': fields.boolean('Interested by this lead'),
|
||||
'contacted': fields.boolean('Did you contact the lead?', help="The lead has been contacted"),
|
||||
'comment': fields.text('Comment', help="What are the elements that have led to this decision?", required=True),
|
||||
}
|
||||
_defaults = {
|
||||
'interested': lambda self, cr, uid, c: c.get('interested', True),
|
||||
'contacted': False,
|
||||
}
|
||||
|
||||
def action_confirm(self, cr, uid, ids, context=None):
|
||||
wizard = self.browse(cr, uid, ids[0], context=context)
|
||||
if wizard.interested and not wizard.contacted:
|
||||
raise osv.except_osv(_('Error!'), _("You must contact the lead before saying that you are interested"))
|
||||
lead_obj = self.pool.get('crm.lead')
|
||||
lead_obj.check_access_rights(cr, uid, 'write')
|
||||
if wizard.interested:
|
||||
message = _('<p>I am interested by this lead.</p>')
|
||||
values = {}
|
||||
else:
|
||||
stage = 'stage_portal_lead_recycle'
|
||||
message = _('<p>I am not interested by this lead. I %scontacted the lead.</p>') % (not wizard.contacted and 'have not ' or '')
|
||||
values = {'partner_assigned_id': False}
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
partner_ids = self.pool.get('res.partner').search(cr, SUPERUSER_ID, [('id', 'child_of', user.partner_id.commercial_partner_id.id)], context=context)
|
||||
lead_obj.message_unsubscribe(cr, SUPERUSER_ID, context.get('active_ids'), partner_ids, context=None)
|
||||
try:
|
||||
stage_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', stage)[1]
|
||||
except ValueError:
|
||||
stage_id = False
|
||||
if stage_id:
|
||||
values.update({'stage_id': stage_id})
|
||||
if wizard.comment:
|
||||
message += '<p>%s</p>' % wizard.comment
|
||||
lead_obj.message_post(cr, uid, context.get('active_ids'), body=message, context=context)
|
||||
if values:
|
||||
lead_obj.write(cr, SUPERUSER_ID, context.get('active_ids'), values)
|
||||
if wizard.interested:
|
||||
for lead in lead_obj.browse(cr, uid, context.get('active_ids'), context=context):
|
||||
lead_obj.convert_opportunity(cr, SUPERUSER_ID, [lead.id], lead.partner_id and lead.partner_id.id or None, context=None)
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'next_or_list',
|
||||
'params': {
|
||||
},
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="crm_lead_channel_interested_form">
|
||||
<field name="name">crm_lead_channel_interested</field>
|
||||
<field name="model">crm.lead.channel.interested</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Send Mail" version="7.0">
|
||||
<group col="1">
|
||||
<field name="interested" nolabel="1" invisible="1"/>
|
||||
<div>
|
||||
<div invisible="context.get('interested', True)">
|
||||
<label for="comment" string="Why aren't you interested by this lead?" />
|
||||
</div>
|
||||
<div invisible="not context.get('interested', True)">
|
||||
<label for="comment" string="What is the next action? When? What is the expected revenue?" />
|
||||
</div>
|
||||
</div>
|
||||
<field name="comment" nolabel="1"/>
|
||||
<div class="oe_inline">
|
||||
<field name="contacted" nolabel="1" string="Do you have contacted the customer?"/>
|
||||
<label for="contacted" />
|
||||
</div>
|
||||
<p class="oe_grey" invisible="not context.get('interested', True)">
|
||||
Once the lead is processed, it will be in your "Opportunities" menu.
|
||||
</p>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="action_confirm" string="Confirm" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" special="cancel" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="crm_lead_channel_interested_act">
|
||||
<field name="name">Lead Feedback</field>
|
||||
<field name="res_model">crm.lead.channel.interested</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="crm_lead_channel_interested_form"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -27,107 +27,182 @@ from openerp.tools.translate import _
|
|||
class crm_lead_forward_to_partner(osv.TransientModel):
|
||||
""" Forward info history to partners. """
|
||||
_name = 'crm.lead.forward.to.partner'
|
||||
_inherit = "mail.compose.message"
|
||||
|
||||
def _get_composition_mode_selection(self, cr, uid, context=None):
|
||||
composition_mode = super(crm_lead_forward_to_partner, self)._get_composition_mode_selection(cr, uid, context=context)
|
||||
composition_mode.append(('forward', 'Forward'))
|
||||
return composition_mode
|
||||
|
||||
_columns = {
|
||||
'partner_ids': fields.many2many('res.partner',
|
||||
'lead_forward_to_partner_res_partner_rel',
|
||||
'wizard_id', 'partner_id', 'Additional contacts'),
|
||||
'attachment_ids': fields.many2many('ir.attachment',
|
||||
'lead_forward_to_partner_attachment_rel',
|
||||
'wizard_id', 'attachment_id', 'Attachments'),
|
||||
'history_mode': fields.selection([('info', 'Internal notes'),
|
||||
('latest', 'Latest email'), ('whole', 'Whole Story')],
|
||||
'Send history', required=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'history_mode': 'info',
|
||||
}
|
||||
def _convert_to_assignation_line(self, cr, uid, lead, partner, context=None):
|
||||
lead_location = []
|
||||
partner_location = []
|
||||
if lead.country_id:
|
||||
lead_location.append(lead.country_id.name)
|
||||
if lead.city:
|
||||
lead_location.append(lead.city)
|
||||
if partner:
|
||||
if partner.country_id:
|
||||
partner_location.append(partner.country_id.name)
|
||||
if partner.city:
|
||||
partner_location.append(partner.city)
|
||||
return {'lead_id': lead.id,
|
||||
'lead_location': ", ".join(lead_location),
|
||||
'partner_assigned_id': partner and partner.id or False,
|
||||
'partner_location': ", ".join(partner_location),
|
||||
'lead_link': self.get_lead_portal_url(cr, uid, lead.id, lead.type, context=context),
|
||||
}
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
# set as comment, perform overrided document-like action that calls get_record_data
|
||||
old_mode = context.get('default_composition_mode', 'forward')
|
||||
context['default_composition_mode'] = 'comment'
|
||||
lead_obj = self.pool.get('crm.lead')
|
||||
email_template_obj = self.pool.get('email.template')
|
||||
try:
|
||||
template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'email_template_lead_forward_mail')[1]
|
||||
except ValueError:
|
||||
template_id = False
|
||||
res = super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context)
|
||||
# back to forward mode
|
||||
context['default_composition_mode'] = old_mode
|
||||
res['composition_mode'] = context['default_composition_mode']
|
||||
active_ids = context.get('active_ids')
|
||||
default_composition_mode = context.get('default_composition_mode')
|
||||
res['assignation_lines'] = []
|
||||
if template_id:
|
||||
res['body'] = email_template_obj.get_email_template(cr, uid, template_id).body_html
|
||||
if active_ids:
|
||||
lead_ids = lead_obj.browse(cr, uid, active_ids, context=context)
|
||||
if default_composition_mode == 'mass_mail':
|
||||
partner_assigned_ids = lead_obj.search_geo_partner(cr, uid, active_ids, context=context)
|
||||
else:
|
||||
partner_assigned_ids = dict((lead.id, lead.partner_assigned_id and lead.partner_assigned_id.id or False) for lead in lead_ids)
|
||||
res['partner_id'] = lead_ids[0].partner_assigned_id.id
|
||||
for lead in lead_ids:
|
||||
partner_id = partner_assigned_ids.get(lead.id) or False
|
||||
partner = False
|
||||
if partner_id:
|
||||
partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
||||
res['assignation_lines'].append(self._convert_to_assignation_line(cr, uid, lead, partner))
|
||||
return res
|
||||
|
||||
def get_record_data(self, cr, uid, model, res_id, context=None):
|
||||
""" Override of mail.compose.message, to add default values coming
|
||||
form the related lead.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
res = super(crm_lead_forward_to_partner, self).get_record_data(cr, uid, model, res_id, context=context)
|
||||
if model not in ('crm.lead') or not res_id:
|
||||
return res
|
||||
template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'crm_partner_assign_email_template')[1]
|
||||
context['history_mode'] = context.get('history_mode','whole')
|
||||
mail_body_fields = ['partner_id', 'partner_name', 'title', 'function', 'street', 'street2', 'zip', 'city', 'country_id', 'state_id', 'email_from', 'phone', 'fax', 'mobile', 'description']
|
||||
lead = self.pool.get('crm.lead').browse(cr, uid, res_id, context=context)
|
||||
context['mail_body'] = self.pool.get('crm.lead')._mail_body(cr, uid, lead, mail_body_fields, context=context)
|
||||
template = self.generate_email_for_composer(cr, uid, template_id, res_id, context)
|
||||
res['subject'] = template['subject']
|
||||
res['body'] = template['body']
|
||||
return res
|
||||
|
||||
def on_change_history_mode(self, cr, uid, ids, history_mode, model, res_id, context=None):
|
||||
""" Update body when changing history_mode """
|
||||
if context is None:
|
||||
context = {}
|
||||
if model and model == 'crm.lead' and res_id:
|
||||
lead = self.pool[model].browse(cr, uid, res_id, context=context)
|
||||
context['history_mode'] = history_mode
|
||||
body = self.get_record_data(cr, uid, 'crm.lead', res_id, context=context)['body']
|
||||
return {'value': {'body': body}}
|
||||
|
||||
def create(self, cr, uid, values, context=None):
|
||||
""" TDE-HACK: remove 'type' from context, because when viewing an
|
||||
opportunity form view, a default_type is set and propagated
|
||||
to the wizard, that has a not matching type field. """
|
||||
default_type = context.pop('default_type', None)
|
||||
new_id = super(crm_lead_forward_to_partner, self).create(cr, uid, values, context=context)
|
||||
if default_type:
|
||||
context['default_type'] = default_type
|
||||
return new_id
|
||||
|
||||
def action_forward(self, cr, uid, ids, context=None):
|
||||
""" Forward the lead to a partner """
|
||||
if context is None:
|
||||
lead_obj = self.pool.get('crm.lead')
|
||||
record = self.browse(cr, uid, ids[0], context=context)
|
||||
email_template_obj = self.pool.get('email.template')
|
||||
try:
|
||||
template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'email_template_lead_forward_mail')[1]
|
||||
except ValueError:
|
||||
raise osv.except_osv(_('Email Template Error'),
|
||||
_('The Forward Email Template is not in the database'))
|
||||
try:
|
||||
portal_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal')[1]
|
||||
except ValueError:
|
||||
raise osv.except_osv(_('Portal Group Error'),
|
||||
_('The Portal group cannot be found'))
|
||||
|
||||
local_context = context.copy()
|
||||
if not (record.forward_type == 'single'):
|
||||
no_email = set()
|
||||
for lead in record.assignation_lines:
|
||||
if lead.partner_assigned_id and not lead.partner_assigned_id.email:
|
||||
no_email.add(lead.partner_assigned_id.name)
|
||||
if no_email:
|
||||
raise osv.except_osv(_('Email Error'),
|
||||
('Set an email address for the partner(s): %s' % ", ".join(no_email)))
|
||||
if record.forward_type == 'single' and not record.partner_id.email:
|
||||
raise osv.except_osv(_('Email Error'),
|
||||
('Set an email address for the partner %s' % record.partner_id.name))
|
||||
|
||||
partners_leads = {}
|
||||
for lead in record.assignation_lines:
|
||||
partner = record.forward_type == 'single' and record.partner_id or lead.partner_assigned_id
|
||||
lead_details = {
|
||||
'lead_link': lead.lead_link,
|
||||
'lead_id': lead.lead_id,
|
||||
}
|
||||
if partner:
|
||||
partner_leads = partners_leads.get(partner.id)
|
||||
if partner_leads:
|
||||
partner_leads['leads'].append(lead_details)
|
||||
else:
|
||||
partners_leads[partner.id] = {'partner': partner, 'leads': [lead_details]}
|
||||
stage_id = False
|
||||
if record.assignation_lines and record.assignation_lines[0].lead_id.type == 'lead':
|
||||
try:
|
||||
stage_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', 'stage_portal_lead_assigned')[1]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
for partner_id, partner_leads in partners_leads.items():
|
||||
in_portal = False
|
||||
for contact in (partner.child_ids or [partner]):
|
||||
if contact.user_ids:
|
||||
in_portal = portal_id in [g.id for g in contact.user_ids[0].groups_id]
|
||||
|
||||
local_context['partner_id'] = partner_leads['partner']
|
||||
local_context['partner_leads'] = partner_leads['leads']
|
||||
local_context['partner_in_portal'] = in_portal
|
||||
email_template_obj.send_mail(cr, uid, template_id, ids[0], context=local_context)
|
||||
lead_ids = [lead['lead_id'].id for lead in partner_leads['leads']]
|
||||
values = {'partner_assigned_id': partner_id, 'user_id': partner_leads['partner'].user_id.id}
|
||||
if stage_id:
|
||||
values['stage_id'] = stage_id
|
||||
lead_obj.write(cr, uid, lead_ids, values)
|
||||
self.pool.get('crm.lead').message_subscribe(cr, uid, lead_ids, [partner_id], context=context)
|
||||
return True
|
||||
|
||||
def get_lead_portal_url(self, cr, uid, lead_id, type, context=None):
|
||||
action = type == 'opportunity' and 'action_portal_opportunities' or 'action_portal_leads'
|
||||
try:
|
||||
action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', action)[1]
|
||||
except ValueError:
|
||||
action_id = False
|
||||
portal_link = "%s/?db=%s#id=%s&action=%s&view_type=form" % (self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url'), cr.dbname, lead_id, action_id)
|
||||
return portal_link
|
||||
|
||||
def get_portal_url(self, cr, uid, ids, context=None):
|
||||
portal_link = "%s/?db=%s" % (self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url'), cr.dbname)
|
||||
return portal_link
|
||||
|
||||
_columns = {
|
||||
'forward_type': fields.selection([('single', 'a single partner: manual selection of partner'), ('assigned', "several partners: automatic assignation, using GPS coordinates and partner's grades"), ], 'Forward selected leads to'),
|
||||
'partner_id': fields.many2one('res.partner', 'Forward Leads To'),
|
||||
'assignation_lines': fields.one2many('crm.lead.assignation', 'forward_id', 'Partner Assignation'),
|
||||
'body': fields.html('Contents', help='Automatically sanitized HTML contents'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'forward_type': lambda self, cr, uid, c: c.get('forward_type') or 'single',
|
||||
}
|
||||
|
||||
|
||||
class crm_lead_assignation (osv.TransientModel):
|
||||
_name = 'crm.lead.assignation'
|
||||
_columns = {
|
||||
'forward_id': fields.many2one('crm.lead.forward.to.partner', 'Partner Assignation'),
|
||||
'lead_id': fields.many2one('crm.lead', 'Lead'),
|
||||
'lead_location': fields.char('Lead Location', size=128),
|
||||
'partner_assigned_id': fields.many2one('res.partner', 'Assigned Partner'),
|
||||
'partner_location': fields.char('Partner Location', size=128),
|
||||
'lead_link': fields.char('Lead Single Links', size=128),
|
||||
}
|
||||
|
||||
def on_change_lead_id(self, cr, uid, ids, lead_id, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
# TDE FIX in 7.0: force mass_mailing mode; this way, the message will be
|
||||
# send only to partners; default subtype of mass_mailing is indeed False
|
||||
# Chatter will show 'logged a note', but partner_ids (aka, the assigned partner)
|
||||
# will effectively receive the message if present in the composition window
|
||||
self.write(cr, uid, ids, {'composition_mode': 'mass_mail'}, context=context)
|
||||
res = {'type': 'ir.actions.act_window_close'}
|
||||
wizard = self.browse(cr, uid, ids[0], context=context)
|
||||
if wizard.model not in ('crm.lead'):
|
||||
return res
|
||||
if context.get('active_ids') is None:
|
||||
context['active_ids'] = [wizard.res_id]
|
||||
if not lead_id:
|
||||
return {'value': {'lead_location': False}}
|
||||
lead = self.pool.get('crm.lead').browse(cr, uid, lead_id, context=context)
|
||||
lead_location = []
|
||||
if lead.country_id:
|
||||
lead_location.append(lead.country_id.name)
|
||||
if lead.city:
|
||||
lead_location.append(lead.city)
|
||||
return {'value': {'lead_location': ", ".join(lead_location)}}
|
||||
|
||||
lead = self.pool[wizard.model]
|
||||
lead_ids = wizard.res_id and [wizard.res_id] or []
|
||||
def on_change_partner_assigned_id(self, cr, uid, ids, partner_assigned_id, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
if not partner_assigned_id:
|
||||
return {'value': {'lead_location': False}}
|
||||
partner = self.pool.get('res.partner').browse(cr, uid, partner_assigned_id, context=context)
|
||||
partner_location = []
|
||||
if partner.country_id:
|
||||
partner_location.append(partner.country_id.name)
|
||||
if partner.city:
|
||||
partner_location.append(partner.city)
|
||||
return {'value': {'partner_location': ", ".join(partner_location)}}
|
||||
|
||||
if wizard.composition_mode == 'mass_mail':
|
||||
lead_ids = context and context.get('active_ids', []) or []
|
||||
value = self.default_get(cr, uid, ['body', 'email_to', 'email_cc', 'subject', 'history_mode'], context=context)
|
||||
value.pop('composition_mode')
|
||||
self.pool.get('crm.lead').message_subscribe(cr, uid, lead_ids, [partner.id for partner in wizard.partner_ids], context=context)
|
||||
self.write(cr, uid, ids, value, context=context)
|
||||
|
||||
return self.send_mail(cr, uid, ids, context=context)
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -1,36 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view" id="crm_lead_forward_to_partner_form">
|
||||
<field name="name">crm_lead_forward_to_partner</field>
|
||||
<field name="model">crm.lead.forward.to.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Send Mail" version="7.0">
|
||||
<field name="composition_mode" colspan="2" nolabel="1" invisible="1"/>
|
||||
<field name="model" colspan="2" nolabel="1" invisible="1"/>
|
||||
<field name="res_id" colspan="2" nolabel="1" invisible="1"/>
|
||||
<separator string="Forward to Partner" colspan="4"/>
|
||||
<group col="4">
|
||||
<field name="history_mode" colspan="4"
|
||||
on_change="on_change_history_mode(history_mode, model, res_id)"/>
|
||||
<field name="subject" colspan="4"/>
|
||||
<field name="partner_ids" colspan="4" widget="many2many_tags_email"/>
|
||||
<notebook colspan="4">
|
||||
<page string="Body">
|
||||
<field name="body"/>
|
||||
</page>
|
||||
<page string="Attachments">
|
||||
<field name="attachment_ids"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<group>
|
||||
<field name="forward_type" widget="radio" invisible="context.get('hide_forward_type',False)"/>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_id" attrs="{'invisible': [('forward_type', 'in', ['assigned',False])], 'required': [('forward_type', '=', 'single')]}" />
|
||||
</group>
|
||||
<group>
|
||||
</group>
|
||||
</group>
|
||||
<field name="assignation_lines" attrs="{'invisible': [('forward_type', 'in', ['single',False])]}">
|
||||
<tree create="false" editable="bottom">
|
||||
<field name="lead_id" readonly="1" on_change="on_change_lead_id(lead_id)"/>
|
||||
<field name="lead_location" readonly="1"/>
|
||||
<field name="partner_assigned_id" on_change="on_change_partner_assigned_id(partner_assigned_id)"/>
|
||||
<field name="partner_location" readonly="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
<notebook colspan="4" groups="base.group_no_one">
|
||||
<page string="Email Template">
|
||||
<field name="body" readonly="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<footer>
|
||||
<button name="action_forward" string="Send" type="object"
|
||||
class="oe_highlight"/>
|
||||
<button name="action_forward" string="Send" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" special="cancel"
|
||||
class="oe_link"/>
|
||||
<button string="Cancel" special="cancel" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -45,14 +47,11 @@
|
|||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<act_window id="action_crm_send_mass_forward"
|
||||
multi="True"
|
||||
key2="client_action_multi" name="Mass forward to partner"
|
||||
res_model="crm.lead.forward.to.partner" src_model="crm.lead"
|
||||
view_mode="form" target="new" view_type="form"
|
||||
context="{'default_composition_mode' : 'mass_mail'}"
|
||||
view_id="crm_lead_forward_to_partner_form"
|
||||
/>
|
||||
<act_window id="action_crm_send_mass_forward" multi="True"
|
||||
key2="client_action_multi" name="Forward to Partner" res_model="crm.lead.forward.to.partner"
|
||||
src_model="crm.lead" view_mode="form" target="new" view_type="form"
|
||||
groups="base.group_sale_manager"
|
||||
context="{'default_composition_mode' : 'mass_mail'}" view_id="crm_lead_forward_to_partner_form" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -25,11 +25,9 @@ class res_partner(osv.osv):
|
|||
_inherit = 'res.partner'
|
||||
_columns = {
|
||||
'property_delivery_carrier': fields.property(
|
||||
'delivery.carrier',
|
||||
type='many2one',
|
||||
relation='delivery.carrier',
|
||||
string="Delivery Method",
|
||||
view_load=True,
|
||||
help="This delivery method will be used when invoicing from picking."),
|
||||
}
|
||||
|
||||
|
|
|
@ -172,6 +172,12 @@ class event_event(osv.osv):
|
|||
continue
|
||||
return res
|
||||
|
||||
def _get_visibility_selection(self, cr, uid, context=None):
|
||||
return [('public', 'All Users'),
|
||||
('employees', 'Employees Only')]
|
||||
# Lambda indirection method to avoid passing a copy of the overridable method when declaring the field
|
||||
_visibility_selection = lambda self, *args, **kwargs: self._get_visibility_selection(*args, **kwargs)
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64, required=True, translate=True, readonly=False, states={'done': [('readonly', True)]}),
|
||||
'user_id': fields.many2one('res.users', 'Responsible User', readonly=False, states={'done': [('readonly', True)]}),
|
||||
|
@ -209,11 +215,14 @@ class event_event(osv.osv):
|
|||
'note': fields.text('Description', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=False, change_default=True, readonly=False, states={'done': [('readonly', True)]}),
|
||||
'is_subscribed' : fields.function(_subscribe_fnc, type="boolean", string='Subscribed'),
|
||||
'visibility': fields.selection(_visibility_selection, 'Privacy / Visibility',
|
||||
select=True, required=True),
|
||||
}
|
||||
_defaults = {
|
||||
'state': 'draft',
|
||||
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'event.event', context=c),
|
||||
'user_id': lambda obj, cr, uid, context: uid,
|
||||
'visibility': 'employees',
|
||||
}
|
||||
|
||||
def subscribe_to_event(self, cr, uid, ids, context=None):
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1><field name="name"/></h1>
|
||||
<field name="visibility"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
|
|
|
@ -25,25 +25,35 @@
|
|||
<data noupdate="1">
|
||||
|
||||
<!-- Multi - Company Rules -->
|
||||
<record model="ir.rule" id="event_event_comp_rule">
|
||||
<field name="name">Event multi-company</field>
|
||||
<record model="ir.rule" id="event_event_company_rule">
|
||||
<field name="name">Event: multi-company</field>
|
||||
<field name="model_id" ref="model_event_event"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
|
||||
<field name="domain_force">['|',
|
||||
('company_id', '=', False),
|
||||
('company_id', 'child_of', [user.company_id.id]),
|
||||
]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="event_registration_comp_rule">
|
||||
<field name="name">Event Registration multi-company</field>
|
||||
<record model="ir.rule" id="event_registration_company_rule">
|
||||
<field name="name">Event/Registration: multi-company</field>
|
||||
<field name="model_id" ref="model_event_registration"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
|
||||
<field name="domain_force">['|',
|
||||
('company_id', '=', False),
|
||||
('company_id', 'child_of', [user.company_id.id]),
|
||||
]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="report_event_registration_comp_rule">
|
||||
<field name="name">Report Event Registration multi-company</field>
|
||||
<record model="ir.rule" id="report_event_registration_company_rule">
|
||||
<field name="name">Event/Report Registration: multi-company</field>
|
||||
<field name="model_id" ref="model_report_event_registration"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
|
||||
<field name="domain_force">['|',
|
||||
('company_id', '=', False),
|
||||
('company_id', 'child_of', [user.company_id.id]),
|
||||
]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -348,12 +348,10 @@
|
|||
<h1><field name="name" class="oe_inline"/></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<group name="job_data">
|
||||
<field name="no_of_employee" groups="base.group_user"/>
|
||||
<field name="no_of_recruitment" on_change="on_change_expected_employee(no_of_recruitment,no_of_employee)"/>
|
||||
<field name="expected_employees" groups="base.group_user"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
<field name="department_id"/>
|
||||
</group>
|
||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-20 05:17+0000\n"
|
||||
"X-Generator: Launchpad (build 16673)\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-21 05:35+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: hr_attendance
|
||||
#: model:ir.model,name:hr_attendance.model_hr_attendance_month
|
||||
|
|
|
@ -0,0 +1,939 @@
|
|||
# Thai translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
|
||||
"PO-Revision-Date: 2013-06-20 10:09+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Thai <th@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-21 05:35+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: model:process.node,name:hr_expense.process_node_confirmedexpenses0
|
||||
msgid "Confirmed Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:ir.model,name:hr_expense.model_hr_expense_line
|
||||
msgid "Expense Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,note:hr_expense.process_node_reimbursement0
|
||||
msgid "The accoutant reimburse the expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:mail.message.subtype,description:hr_expense.mt_expense_approved
|
||||
msgid "Expense approved"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,date_confirm:0
|
||||
#: field:hr.expense.report,date_confirm:0
|
||||
msgid "Confirmation Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: view:hr.expense.report:0
|
||||
msgid "Group By..."
|
||||
msgstr "จัดกลุ่มตาม..."
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:product.template,name:hr_expense.air_ticket_product_template
|
||||
msgid "Air Ticket"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "Validated By"
|
||||
msgstr "ตรวจสอบโดย"
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: field:hr.expense.expense,department_id:0
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,department_id:0
|
||||
msgid "Department"
|
||||
msgstr "แผนก"
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "New Expense"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.line,uom_id:0
|
||||
#: view:product.product:0
|
||||
msgid "Unit of Measure"
|
||||
msgstr "หน่วยของการวัด"
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "March"
|
||||
msgstr "มีนาคม"
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,message_unread:0
|
||||
msgid "Unread Messages"
|
||||
msgstr "ข้อความที่ไม่ได้อ่าน"
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,company_id:0
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,company_id:0
|
||||
msgid "Company"
|
||||
msgstr "บริษัท"
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Set to Draft"
|
||||
msgstr "กำหนดให้เป็นแบบร่าง"
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "To Pay"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:172
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No expense journal found. Please make sure you have a journal with type "
|
||||
"'purchase' configured."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:ir.model,name:hr_expense.model_hr_expense_report
|
||||
msgid "Expenses Statistics"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Open Receipt"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,day:0
|
||||
msgid "Day"
|
||||
msgstr "วัน"
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:hr.expense.expense,date_valid:0
|
||||
msgid ""
|
||||
"Date of the acceptation of the sheet expense. It's filled when the button "
|
||||
"Accept is pressed."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Notes"
|
||||
msgstr "บันทึกย่อ"
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,message_ids:0
|
||||
msgid "Messages"
|
||||
msgstr "ข้อความ"
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:172
|
||||
#: code:addons/hr_expense/hr_expense.py:238
|
||||
#: code:addons/hr_expense/hr_expense.py:240
|
||||
#: code:addons/hr_expense/hr_expense.py:349
|
||||
#: code:addons/hr_expense/hr_expense.py:353
|
||||
#, python-format
|
||||
msgid "Error!"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:mail.message.subtype,description:hr_expense.mt_expense_refused
|
||||
msgid "Expense refused"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:ir.actions.act_window,name:hr_expense.hr_expense_product
|
||||
#: view:product.product:0
|
||||
msgid "Products"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
msgid "Confirm Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,state:0
|
||||
msgid "Cancelled"
|
||||
msgstr "ยกเลิกแล้ว"
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,note:hr_expense.process_node_refused0
|
||||
msgid "The direct manager refuses the sheet.Reset as draft."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:hr.expense.expense,message_unread:0
|
||||
msgid "If checked new messages require your attention."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,state:0
|
||||
msgid "Waiting confirmation"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,state:0
|
||||
msgid "Accepted"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.line,ref:0
|
||||
msgid "Reference"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "Certified honest and conform,"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:hr.expense.expense,state:0
|
||||
msgid ""
|
||||
"When the expense request is created the status is 'Draft'.\n"
|
||||
" It is confirmed by the user and request is sent to admin, the status is "
|
||||
"'Waiting Confirmation'. \n"
|
||||
"If the admin accepts it, the status is 'Accepted'.\n"
|
||||
" If a receipt is made for the expense request, the status is 'Done'."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:hr.expense.expense,date_confirm:0
|
||||
msgid ""
|
||||
"Date of the confirmation of the sheet expense. It's filled when the button "
|
||||
"Confirm is pressed."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,nbr:0
|
||||
msgid "# of Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:hr.expense.expense,message_summary:0
|
||||
msgid ""
|
||||
"Holds the Chatter summary (number of messages, ...). This summary is "
|
||||
"directly in html format in order to be inserted in kanban views."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:453
|
||||
#, python-format
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "(Date and signature)"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "Total:"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,name:hr_expense.process_transition_refuseexpense0
|
||||
msgid "Refuse expense"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.report,price_average:0
|
||||
msgid "Average Price"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: model:process.transition.action,name:hr_expense.process_transition_action_confirm0
|
||||
msgid "Confirm"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,note:hr_expense.process_node_supplierinvoice0
|
||||
msgid "The accoutant validates the sheet"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.report,delay_valid:0
|
||||
msgid "Delay to Valid"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:hr.expense.line,sequence:0
|
||||
msgid "Gives the sequence order when displaying a list of expense lines."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,state:0
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,state:0
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.line,analytic_account:0
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,analytic_account:0
|
||||
msgid "Analytic account"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.report,date:0
|
||||
msgid "Date "
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
msgid "Waiting"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,message_follower_ids:0
|
||||
msgid "Followers"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
#: view:hr.expense.expense:0
|
||||
#: field:hr.expense.expense,employee_id:0
|
||||
#: view:hr.expense.report:0
|
||||
msgid "Employee"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: selection:hr.expense.expense,state:0
|
||||
msgid "New"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
#: field:hr.expense.report,product_qty:0
|
||||
msgid "Qty"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,price_total:0
|
||||
msgid "Total Price"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,note:hr_expense.process_node_reinvoicing0
|
||||
msgid "Some costs may be reinvoices to the customer"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:238
|
||||
#, python-format
|
||||
msgid "The employee must have a home address."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:board.board:0
|
||||
#: view:hr.expense.expense:0
|
||||
#: model:ir.actions.act_window,name:hr_expense.action_my_expense
|
||||
msgid "My Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
msgid "Creation Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:ir.actions.report.xml,name:hr_expense.hr_expenses
|
||||
msgid "HR expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,id:0
|
||||
msgid "Sheet ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,name:hr_expense.process_transition_reimburseexpense0
|
||||
msgid "Reimburse expense"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,journal_id:0
|
||||
#: field:hr.expense.report,journal_id:0
|
||||
msgid "Force Journal"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,no_of_products:0
|
||||
msgid "# of Products"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "July"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,note:hr_expense.process_transition_reimburseexpense0
|
||||
msgid "After creating invoice, reimburse expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:121
|
||||
#, python-format
|
||||
msgid "Warning!"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,name:hr_expense.process_node_reimbursement0
|
||||
msgid "Reimbursement"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,date_valid:0
|
||||
#: field:hr.expense.report,date_valid:0
|
||||
msgid "Validation Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:226
|
||||
#, python-format
|
||||
msgid "Expense Receipt"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
#: model:ir.actions.act_window,name:hr_expense.action_hr_expense_report_all
|
||||
#: model:ir.ui.menu,name:hr_expense.menu_hr_expense_report_all
|
||||
msgid "Expenses Analysis"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: field:hr.expense.line,expense_id:0
|
||||
#: model:ir.model,name:hr_expense.model_hr_expense_expense
|
||||
#: model:process.process,name:hr_expense.process_process_expenseprocess0
|
||||
msgid "Expense"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: field:hr.expense.expense,line_ids:0
|
||||
#: view:hr.expense.line:0
|
||||
msgid "Expense Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.report,delay_confirm:0
|
||||
msgid "Delay to Confirm"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "September"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "December"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,month:0
|
||||
msgid "Month"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,currency_id:0
|
||||
#: field:hr.expense.report,currency_id:0
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,voucher_id:0
|
||||
msgid "Employee's Receipt"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.expense,state:0
|
||||
msgid "Waiting Approval"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,note:hr_expense.process_node_draftexpenses0
|
||||
msgid "Employee encode all his expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:453
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Selected Unit of Measure does not belong to the same category as the product "
|
||||
"Unit of Measure"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:hr.expense.expense,journal_id:0
|
||||
msgid "The journal used when the expense is done."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,note:0
|
||||
msgid "Note"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,note:hr_expense.process_transition_reimbursereinvoice0
|
||||
msgid "Create Customer invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,state:0
|
||||
msgid "Draft"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:353
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please configure Default Expense account for Product purchase: "
|
||||
"`property_account_expense_categ`."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,note:hr_expense.process_transition_approveexpense0
|
||||
msgid "Expense is approved."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "August"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,note:hr_expense.process_node_approved0
|
||||
msgid "The direct manager approves the sheet"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: field:hr.expense.expense,amount:0
|
||||
msgid "Total Amount"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "June"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,name:hr_expense.process_node_draftexpenses0
|
||||
msgid "Draft Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,message_is_follower:0
|
||||
msgid "Is a Follower"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:ir.actions.act_window,name:hr_expense.product_normal_form_view_installer
|
||||
msgid "Review Your Expenses Products"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
#: field:hr.expense.expense,date:0
|
||||
#: field:hr.expense.line,date_value:0
|
||||
msgid "Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "November"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
msgid "Extended Filters..."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,user_id:0
|
||||
msgid "User"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:ir.ui.menu,name:hr_expense.menu_hr_product
|
||||
msgid "Expense Categories"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "October"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:ir.actions.act_window,help:hr_expense.expense_all
|
||||
msgid ""
|
||||
"<p class=\"oe_view_nocontent_create\">\n"
|
||||
" Click to register new expenses. \n"
|
||||
" </p><p>\n"
|
||||
" OpenERP will ensure the whole process is followed; the "
|
||||
"expense\n"
|
||||
" sheet is validated by manager(s), the employee is "
|
||||
"reimbursed\n"
|
||||
" from his expenses, some expenses must be re-invoiced to the\n"
|
||||
" customers.\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Generate Accounting Entries"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "January"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "HR Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,message_summary:0
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:product.template,name:hr_expense.car_travel_product_template
|
||||
msgid "Car Travel Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Submit to Manager"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
msgid "Done Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,note:hr_expense.process_node_confirmedexpenses0
|
||||
msgid "The employee validates his expense sheet"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Expenses to Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,name:hr_expense.process_node_supplierinvoice0
|
||||
#: model:process.transition,name:hr_expense.process_transition_approveinvoice0
|
||||
msgid "Supplier Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Expenses Sheet"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.report,voucher_id:0
|
||||
msgid "Receipt"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
msgid "Approved Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
#: field:hr.expense.line,unit_amount:0
|
||||
msgid "Unit Price"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
#: selection:hr.expense.report,state:0
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition.action,name:hr_expense.process_transition_action_supplierinvoice0
|
||||
msgid "Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,year:0
|
||||
msgid "Year"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,name:hr_expense.process_transition_reimbursereinvoice0
|
||||
msgid "Reinvoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Expense Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,user_valid:0
|
||||
msgid "Validation By"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: model:process.transition.action,name:hr_expense.process_transition_action_refuse0
|
||||
msgid "Refuse"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,name:hr_expense.process_transition_confirmexpense0
|
||||
msgid "Confirm expense"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,name:hr_expense.process_transition_approveexpense0
|
||||
msgid "Approve expense"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition.action,name:hr_expense.process_transition_action_accept0
|
||||
msgid "Accept"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "This document must be dated and signed for reimbursement"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,note:hr_expense.process_transition_refuseexpense0
|
||||
msgid "Expense is refused."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:ir.actions.act_window,help:hr_expense.product_normal_form_view_installer
|
||||
msgid ""
|
||||
"Define one product for each expense type allowed for an employee (travel by "
|
||||
"car, hostel, restaurant, etc). If you reimburse the employees at a fixed "
|
||||
"rate, set a cost and a unit of measure on the product. If you reimburse "
|
||||
"based on real costs, set the cost at 0.00. The user will set the real price "
|
||||
"when recording his expense sheet."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.expense,state:0
|
||||
#: view:hr.expense.report:0
|
||||
#: model:mail.message.subtype,name:hr_expense.mt_expense_approved
|
||||
#: model:process.node,name:hr_expense.process_node_approved0
|
||||
msgid "Approved"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.line,product_id:0
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,product_id:0
|
||||
#: model:ir.model,name:hr_expense.model_product_product
|
||||
msgid "Product"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
#: view:hr.expense.expense:0
|
||||
#: field:hr.expense.expense,name:0
|
||||
#: field:hr.expense.line,description:0
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.line,unit_quantity:0
|
||||
msgid "Quantities"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "Price"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.report,no_of_account:0
|
||||
msgid "# of Accounts"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.expense,state:0
|
||||
#: model:mail.message.subtype,name:hr_expense.mt_expense_refused
|
||||
#: model:process.node,name:hr_expense.process_node_refused0
|
||||
msgid "Refused"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:product.product,hr_expense_ok:0
|
||||
msgid "Can be Expensed"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:mail.message.subtype,description:hr_expense.mt_expense_confirmed
|
||||
msgid "Expense confirmed, waiting confirmation"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "Ref."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.report,employee_id:0
|
||||
msgid "Employee's Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.report:0
|
||||
#: field:hr.expense.report,user_id:0
|
||||
msgid "Validation User"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Accounting Data"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "February"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: report:hr.expense:0
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: code:addons/hr_expense/hr_expense.py:121
|
||||
#, python-format
|
||||
msgid "You can only delete draft expenses!"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.expense,account_move_id:0
|
||||
msgid "Ledger Posting"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,note:hr_expense.process_transition_approveinvoice0
|
||||
msgid "Creates supplier invoice."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:product.template,name:hr_expense.hotel_rent_product_template
|
||||
msgid "Hotel Accommodation"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: selection:hr.expense.report,month:0
|
||||
msgid "April"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.line,name:0
|
||||
msgid "Expense Note"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Approve"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:hr.expense.expense,message_ids:0
|
||||
msgid "Messages and communication history"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: field:hr.expense.line,sequence:0
|
||||
msgid "Sequence"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.transition,note:hr_expense.process_transition_confirmexpense0
|
||||
msgid "Expense is confirmed."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: model:ir.actions.act_window,name:hr_expense.expense_all
|
||||
#: model:ir.ui.menu,name:hr_expense.menu_expense_all
|
||||
#: model:ir.ui.menu,name:hr_expense.next_id_49
|
||||
#: model:product.category,name:hr_expense.cat_expense
|
||||
msgid "Expenses"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: help:product.product,hr_expense_ok:0
|
||||
msgid "Specify if the product can be selected in an HR expense line."
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
msgid "Accounting"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: model:mail.message.subtype,name:hr_expense.mt_expense_confirmed
|
||||
msgid "To Approve"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: view:hr.expense.expense:0
|
||||
#: view:hr.expense.line:0
|
||||
#: field:hr.expense.line,total_amount:0
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#. module: hr_expense
|
||||
#: model:process.node,name:hr_expense.process_node_reinvoicing0
|
||||
msgid "Reinvoicing"
|
||||
msgstr ""
|
|
@ -7,14 +7,14 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 6.0dev\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
|
||||
"PO-Revision-Date: 2012-12-14 12:51+0000\n"
|
||||
"Last-Translator: Grzegorz Grzelak (OpenGLOBE.pl) <grzegorz@openglobe.pl>\n"
|
||||
"PO-Revision-Date: 2013-06-22 10:54+0000\n"
|
||||
"Last-Translator: Dariusz Kubiak <d.kubiak@macopedia.pl>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-03-16 05:30+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-23 05:13+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: selection:hr.holidays.status,color_name:0
|
||||
|
@ -32,7 +32,7 @@ msgid "Waiting Second Approval"
|
|||
msgstr "Oczekuje na drugą aprobatę"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:298
|
||||
#: code:addons/hr_holidays/hr_holidays.py:309
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot modify a leave request that has been approved. Contact a human "
|
||||
|
@ -109,11 +109,13 @@ msgid ""
|
|||
"The default duration interval between the start date and the end date is 8 "
|
||||
"hours. Feel free to adapt it to your needs."
|
||||
msgstr ""
|
||||
"Domyślny odstęp między datą rozpoczęcia i data zakończenia jest 8 godzin. "
|
||||
"Zapraszam do dostosowania go do swoich potrzeb."
|
||||
|
||||
#. module: hr_holidays
|
||||
#: model:mail.message.subtype,description:hr_holidays.mt_holidays_refused
|
||||
msgid "Request refused"
|
||||
msgstr ""
|
||||
msgstr "Wniosek odrzucony"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: field:hr.holidays,number_of_days_temp:0
|
||||
|
@ -274,12 +276,12 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:238
|
||||
#: code:addons/hr_holidays/hr_holidays.py:249
|
||||
#: code:addons/hr_holidays/hr_holidays.py:274
|
||||
#: code:addons/hr_holidays/hr_holidays.py:298
|
||||
#: code:addons/hr_holidays/hr_holidays.py:421
|
||||
#: code:addons/hr_holidays/hr_holidays.py:471
|
||||
#: code:addons/hr_holidays/hr_holidays.py:260
|
||||
#: code:addons/hr_holidays/hr_holidays.py:285
|
||||
#: code:addons/hr_holidays/hr_holidays.py:309
|
||||
#: code:addons/hr_holidays/hr_holidays.py:432
|
||||
#: code:addons/hr_holidays/hr_holidays.py:482
|
||||
#, python-format
|
||||
msgid "Warning!"
|
||||
msgstr "Ostrzeżenie !"
|
||||
|
@ -317,7 +319,7 @@ msgid "Sick Leaves"
|
|||
msgstr "Zwolnienie lekarskie"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:478
|
||||
#: code:addons/hr_holidays/hr_holidays.py:489
|
||||
#, python-format
|
||||
msgid "Leave Request for %s"
|
||||
msgstr "Wniosek urlopowy dla %s"
|
||||
|
@ -341,7 +343,7 @@ msgstr "Pozostało dni urlopu"
|
|||
#. module: hr_holidays
|
||||
#: field:hr.holidays,message_follower_ids:0
|
||||
msgid "Followers"
|
||||
msgstr ""
|
||||
msgstr "Obserwatorzy"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: model:ir.model,name:hr_holidays.model_hr_holidays_remaining_leaves_user
|
||||
|
@ -388,7 +390,7 @@ msgid "Wheat"
|
|||
msgstr "Pszenny"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:476
|
||||
#: code:addons/hr_holidays/hr_holidays.py:487
|
||||
#, python-format
|
||||
msgid "Allocation for %s"
|
||||
msgstr "Przydział dla %s"
|
||||
|
@ -412,7 +414,7 @@ msgid "Number of Days"
|
|||
msgstr "Liczba dni"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:471
|
||||
#: code:addons/hr_holidays/hr_holidays.py:482
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The feature behind the field 'Remaining Legal Leaves' can only be used when "
|
||||
|
@ -516,7 +518,7 @@ msgid "Start Date"
|
|||
msgstr "Data początkowa"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:421
|
||||
#: code:addons/hr_holidays/hr_holidays.py:432
|
||||
#, python-format
|
||||
msgid ""
|
||||
"There are not enough %s allocated for employee %s; please create an "
|
||||
|
@ -678,7 +680,7 @@ msgstr "Podsumowanie"
|
|||
#. module: hr_holidays
|
||||
#: model:hr.holidays.status,name:hr_holidays.holiday_status_unpaid
|
||||
msgid "Unpaid"
|
||||
msgstr "Niezapłacone"
|
||||
msgstr "Bezpłatny"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: xsl:holidays.summary:0
|
||||
|
@ -741,7 +743,7 @@ msgstr "Różne"
|
|||
#. module: hr_holidays
|
||||
#: model:hr.holidays.status,name:hr_holidays.holiday_status_comp
|
||||
msgid "Compensatory Days"
|
||||
msgstr ""
|
||||
msgstr "Urlop wyrównawczy"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: selection:hr.holidays.status,color_name:0
|
||||
|
@ -766,7 +768,7 @@ msgid "Validated"
|
|||
msgstr "Zatwierdzony"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:238
|
||||
#: code:addons/hr_holidays/hr_holidays.py:249
|
||||
#, python-format
|
||||
msgid "You cannot delete a leave which is in %s state."
|
||||
msgstr "Nie możesz usunąć nieobecności, która jest w stanie %s."
|
||||
|
@ -830,7 +832,7 @@ msgid "To Submit"
|
|||
msgstr "Do wysłania"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:343
|
||||
#: code:addons/hr_holidays/hr_holidays.py:354
|
||||
#: view:hr.holidays:0
|
||||
#: selection:hr.holidays,type:0
|
||||
#: field:resource.calendar.leaves,holiday_id:0
|
||||
|
@ -930,8 +932,8 @@ msgid "Messages and communication history"
|
|||
msgstr "Wiadomości i historia komunikacji"
|
||||
|
||||
#. module: hr_holidays
|
||||
#: code:addons/hr_holidays/hr_holidays.py:249
|
||||
#: code:addons/hr_holidays/hr_holidays.py:274
|
||||
#: code:addons/hr_holidays/hr_holidays.py:260
|
||||
#: code:addons/hr_holidays/hr_holidays.py:285
|
||||
#: sql_constraint:hr.holidays:0
|
||||
#, python-format
|
||||
msgid "The start date must be anterior to the end date."
|
||||
|
|
|
@ -506,33 +506,18 @@ class hr_job(osv.osv):
|
|||
help="Email alias for this job position. New emails will automatically "
|
||||
"create new applicants for this job position."),
|
||||
}
|
||||
_defaults = {
|
||||
'alias_domain': False, # always hide alias during creation
|
||||
}
|
||||
|
||||
def _auto_init(self, cr, context=None):
|
||||
"""Installation hook to create aliases for all jobs and avoid constraint errors."""
|
||||
if context is None:
|
||||
context = {}
|
||||
alias_context = dict(context, alias_model_name='hr.applicant')
|
||||
res = self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(hr_job, self)._auto_init,
|
||||
self._columns['alias_id'], 'name', alias_prefix='job+', alias_defaults={'job_id': 'id'}, context=alias_context)
|
||||
return res
|
||||
return self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(hr_job, self)._auto_init,
|
||||
'hr.applicant', self._columns['alias_id'], 'name', alias_prefix='job+', alias_defaults={'job_id': 'id'}, context=context)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
mail_alias = self.pool.get('mail.alias')
|
||||
if not vals.get('alias_id'):
|
||||
vals.pop('alias_name', None) # prevent errors during copy()
|
||||
alias_id = mail_alias.create_unique_alias(cr, uid,
|
||||
# Using '+' allows using subaddressing for those who don't
|
||||
# have a catchall domain setup.
|
||||
{'alias_name': 'jobs+'+vals['name']},
|
||||
model_name="hr.applicant",
|
||||
context=context)
|
||||
vals['alias_id'] = alias_id
|
||||
res = super(hr_job, self).create(cr, uid, vals, context)
|
||||
mail_alias.write(cr, uid, [vals['alias_id']], {"alias_defaults": {'job_id': res}}, context)
|
||||
return res
|
||||
alias_context = dict(context, alias_model_name='hr.applicant', alias_parent_model_name=self._name)
|
||||
job_id = super(hr_job, self).create(cr, uid, vals, context=alias_context)
|
||||
job = self.browse(cr, uid, job_id, context=context)
|
||||
self.pool.get('mail.alias').write(cr, uid, [job.alias_id.id], {'alias_parent_thread_id': job_id, "alias_defaults": {'job_id': job_id}}, context)
|
||||
return job_id
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
# Cascade-delete mail aliases as well, as they should not exist without the job position.
|
||||
|
@ -550,15 +535,16 @@ class hr_job(osv.osv):
|
|||
if record.survey_id:
|
||||
datas['ids'] = [record.survey_id.id]
|
||||
datas['model'] = 'survey.print'
|
||||
context.update({'response_id': [0], 'response_no': 0,})
|
||||
context.update({'response_id': [0], 'response_no': 0})
|
||||
return {
|
||||
'type': 'ir.actions.report.xml',
|
||||
'report_name': 'survey.form',
|
||||
'datas': datas,
|
||||
'context' : context,
|
||||
'nodestroy':True,
|
||||
'context': context,
|
||||
'nodestroy': True,
|
||||
}
|
||||
|
||||
|
||||
class applicant_category(osv.osv):
|
||||
""" Category of applicant """
|
||||
_name = "hr.applicant_category"
|
||||
|
|
|
@ -316,18 +316,19 @@
|
|||
attrs="{'invisible':[('survey_id','=',False)]}"/>
|
||||
</div>
|
||||
</field>
|
||||
<xpath expr="//div[@class='oe_title']//h1" position="after">
|
||||
<div name="group_alias"
|
||||
<xpath expr="//group[@name='job_data']" position="after">
|
||||
<group name="group_alias"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}">
|
||||
<label for="alias_id" string="Email Alias"/>
|
||||
<field name="alias_id" class="oe_inline oe_read_only" required="0" nolabel="1"/>
|
||||
<span name="edit_alias" class="oe_edit_only">
|
||||
<field name="alias_name" class="oe_inline"
|
||||
attrs="{'required': [('alias_id', '!=', False)]}"/>
|
||||
@
|
||||
<field name="alias_domain" class="oe_inline" readonly="1"/>
|
||||
</span>
|
||||
</div>
|
||||
<label for="alias_name" string="Email Alias"/>
|
||||
<div name="alias_def">
|
||||
<field name="alias_id" class="oe_read_only oe_inline"
|
||||
string="Email Alias" required="0"/>
|
||||
<div class="oe_edit_only oe_inline" name="edit_alias" style="display: inline;" >
|
||||
<field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
|
||||
</div>
|
||||
</div>
|
||||
<field name="alias_contact" class="oe_inline" string="Accept Emails From"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -14,8 +14,8 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-20 05:17+0000\n"
|
||||
"X-Generator: Launchpad (build 16673)\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-21 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: hr_recruitment
|
||||
#: help:hr.applicant,active:0
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-Today OpenERP S.A. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -19,5 +19,4 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import idea
|
||||
|
||||
import models
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-Today OpenERP S.A. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -22,29 +22,39 @@
|
|||
|
||||
{
|
||||
'name': 'Ideas',
|
||||
'version': '0.1',
|
||||
'summary': 'Share and Discuss your Ideas',
|
||||
'version': '1.0',
|
||||
'category': 'Tools',
|
||||
'description': """
|
||||
This module allows user to easily and efficiently participate in enterprise innovation.
|
||||
=======================================================================================
|
||||
Share your ideas and participate in enterprise innovation
|
||||
=========================================================
|
||||
|
||||
It allows everybody to express ideas about different subjects.
|
||||
Then, other users can comment on these ideas and vote for particular ideas.
|
||||
Each idea has a score based on the different votes.
|
||||
The Ideas module give users a way to express and discuss ideas, allowing everybody
|
||||
to participate in enterprise innovation. Every user can suggest, comment ideas.
|
||||
The managers can obtain an easy view of best ideas from all the users.
|
||||
Once installed, check the menu 'Ideas' in the 'Tools' main menu.""",
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'http://openerp.com',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['mail'],
|
||||
'data': [
|
||||
'security/idea_security.xml',
|
||||
'security/idea.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'idea_view.xml',
|
||||
'idea_workflow.xml',
|
||||
'views/idea.xml',
|
||||
'views/category.xml',
|
||||
'data/idea.xml',
|
||||
'data/idea_workflow.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/idea.xml',
|
||||
],
|
||||
'demo': ['idea_data.xml'],
|
||||
'test':[],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'images': [],
|
||||
'css': [
|
||||
'static/src/css/idea_idea.css',
|
||||
],
|
||||
'js': [],
|
||||
'qweb': [],
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="workflow" id="wkf_idea">
|
||||
<field name="name">idea.wkf</field>
|
||||
<field name="osv">idea.idea</field>
|
||||
<field name="on_create">True</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_normal">
|
||||
<field name="wkf_id" ref="wkf_idea" />
|
||||
<field name="flow_start">True</field>
|
||||
<field name="name">normal</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">idea_set_normal_priority()</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_low">
|
||||
<field name="wkf_id" ref="wkf_idea" />
|
||||
<field name="name">low</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">idea_set_low_priority()</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_high">
|
||||
<field name="wkf_id" ref="wkf_idea" />
|
||||
<field name="name">high</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">idea_set_high_priority()</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t1">
|
||||
<field name="act_from" ref="act_normal" />
|
||||
<field name="act_to" ref="act_low" />
|
||||
<field name="signal">idea_set_low_priority</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t2">
|
||||
<field name="act_from" ref="act_low" />
|
||||
<field name="act_to" ref="act_normal" />
|
||||
<field name="signal">idea_set_normal_priority</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t3">
|
||||
<field name="act_from" ref="act_normal" />
|
||||
<field name="act_to" ref="act_high" />
|
||||
<field name="signal">idea_set_high_priority</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t4">
|
||||
<field name="act_from" ref="act_high" />
|
||||
<field name="act_to" ref="act_normal" />
|
||||
<field name="signal">idea_set_normal_priority</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="idea.category" id="idea_cat_0">
|
||||
<field name="name">Sales</field>
|
||||
</record>
|
||||
<record model="idea.category" id="idea_cat_1">
|
||||
<field name="name">Organization</field>
|
||||
</record>
|
||||
<record model="idea.category" id="idea_cat_2">
|
||||
<field name="name">Technical</field>
|
||||
</record>
|
||||
|
||||
<record model="idea.idea" id="idea_idea_0">
|
||||
<field name="name">Docking station along with tablet PC</field>
|
||||
<field name="description">When you sell a tablet PC, maybe we could propose a docking station with it. I offer 20% on the docking stating (not the tablet).</field>
|
||||
<field name="user_id" eval="ref('base.user_demo')"/>
|
||||
<field name="category_ids" eval="[(6, 0, [ref('idea.idea_cat_0')])]"/>
|
||||
</record>
|
||||
|
||||
<record model="idea.idea" id="idea_idea_1">
|
||||
<field name="name">Communicate using emails</field>
|
||||
<field name="description">I start communicating with prospects more by email than phonecalls. I send an email to create a sense of emergency, like "can I call you this week about our quote?" and I call only those that answer this email.</field>
|
||||
<field name="user_id" eval="ref('base.user_demo')"/>
|
||||
<field name="state">open</field>
|
||||
<field name="category_ids" eval="[(6, 0, [ref('idea.idea_cat_0'), ref('idea.idea_cat_1')])]"/>
|
||||
</record>
|
||||
<workflow action="idea_set_high_priority" model="idea.idea" ref="idea_idea_1"/>
|
||||
|
||||
<record model="idea.idea" id="idea_idea_2">
|
||||
<field name="name">Use a two-stages testing phase</field>
|
||||
<field name="description">We should perform testing using two levels of validation.</field>
|
||||
<field name="user_id" eval="ref('base.user_root')"/>
|
||||
<field name="state">open</field>
|
||||
<field name="category_ids" eval="[(6, 0, [ref('idea.idea_cat_1'), ref('idea.idea_cat_2')])]"/>
|
||||
</record>
|
||||
<workflow action="idea_set_high_priority" model="idea.idea" ref="idea_idea_2"/>
|
||||
|
||||
<record model="idea.idea" id="idea_idea_3">
|
||||
<field name="name">Write some functional documentation about procurements</field>
|
||||
<field name="description">We receive many questions about OpenChatter. Maybe some functional doc could save us some time.</field>
|
||||
<field name="user_id" eval="ref('base.user_demo')"/>
|
||||
<field name="state">open</field>
|
||||
<field name="category_ids" eval="[(6, 0, [ref('idea.idea_cat_0'), ref('idea.idea_cat_1')])]"/>
|
||||
</record>
|
||||
|
||||
<record model="idea.idea" id="idea_idea_4">
|
||||
<field name="name">Better management of smtp errors</field>
|
||||
<field name="description">There should be away to store the reason why some emails are not sent.</field>
|
||||
<field name="user_id" eval="ref('base.user_root')"/>
|
||||
<field name="state">close</field>
|
||||
<field name="category_ids" eval="[(6, 0, [ref('idea.idea_cat_2')])]"/>
|
||||
</record>
|
||||
<workflow action="idea_set_low_priority" model="idea.idea" ref="idea_idea_4"/>
|
||||
|
||||
<record model="idea.idea" id="idea_idea_5">
|
||||
<field name="name">Kitten mode enabled by default</field>
|
||||
<field name="description">As this is the most loved feature, the kitten mode should be enabled by default. And maybe even impossible to remove.</field>
|
||||
<field name="user_id" eval="ref('base.user_root')"/>
|
||||
<field name="state">cancel</field>
|
||||
<field name="category_ids" eval="[(6, 0, [ref('idea.idea_cat_2')])]"/>
|
||||
</record>
|
||||
<workflow action="idea_set_low_priority" model="idea.idea" ref="idea_idea_4"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv
|
||||
from openerp.osv import fields
|
||||
from openerp.tools.translate import _
|
||||
import time
|
||||
|
||||
VoteValues = [('-1', 'Not Voted'), ('0', 'Very Bad'), ('25', 'Bad'), \
|
||||
('50', 'Normal'), ('75', 'Good'), ('100', 'Very Good') ]
|
||||
DefaultVoteValue = '50'
|
||||
|
||||
class idea_category(osv.osv):
|
||||
""" Category of Idea """
|
||||
_name = "idea.category"
|
||||
_description = "Idea Category"
|
||||
_columns = {
|
||||
'name': fields.char('Category Name', size=64, required=True),
|
||||
}
|
||||
_sql_constraints = [
|
||||
('name', 'unique(name)', 'The name of the category must be unique')
|
||||
]
|
||||
_order = 'name asc'
|
||||
|
||||
|
||||
class idea_idea(osv.osv):
|
||||
""" Idea """
|
||||
_name = 'idea.idea'
|
||||
_inherit = ['mail.thread']
|
||||
_columns = {
|
||||
'create_uid': fields.many2one('res.users', 'Creator', required=True, readonly=True),
|
||||
'name': fields.char('Idea Summary', size=64, required=True, readonly=True, oldname='title', states={'draft': [('readonly', False)]}),
|
||||
'description': fields.text('Description', help='Content of the idea', readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'category_ids': fields.many2many('idea.category', string='Tags', readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'state': fields.selection([('draft', 'New'),
|
||||
('open', 'Accepted'),
|
||||
('cancel', 'Refused'),
|
||||
('close', 'Done')],
|
||||
'Status', readonly=True, track_visibility='onchange',
|
||||
)
|
||||
}
|
||||
_sql_constraints = [
|
||||
('name', 'unique(name)', 'The name of the idea must be unique')
|
||||
]
|
||||
_defaults = {
|
||||
'state': lambda *a: 'draft',
|
||||
}
|
||||
_order = 'name asc'
|
||||
|
||||
def idea_cancel(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
|
||||
|
||||
def idea_open(self, cr, uid, ids, context={}):
|
||||
return self.write(cr, uid, ids, {'state': 'open'}, context=context)
|
||||
|
||||
def idea_close(self, cr, uid, ids, context={}):
|
||||
return self.write(cr, uid, ids, {'state': 'close'}, context=context)
|
||||
|
||||
def idea_draft(self, cr, uid, ids, context={}):
|
||||
return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="idea.category" id="idea_category_sales">
|
||||
<field name="name">Sales</field>
|
||||
</record>
|
||||
<record model="idea.category" id="idea_category_general">
|
||||
<field name="name">Organization</field>
|
||||
</record>
|
||||
<record model="idea.category" id="idea_category_technical">
|
||||
<field name="name">Technical</field>
|
||||
</record>
|
||||
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('base.group_tool_user'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- Top menu item -->
|
||||
<menuitem name="Tools" id="base.menu_tools" sequence="120" groups="base.group_tool_user"/>
|
||||
<!-- Idea Categories Search View-->
|
||||
<record model="ir.ui.view" id="view_idea_category_search">
|
||||
<field name="name">idea.category.search</field>
|
||||
<field name="model">idea.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Ideas Categories">
|
||||
<field name="name" string="Category"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Idea Category Form View -->
|
||||
<record model="ir.ui.view" id="view_idea_category_form">
|
||||
<field name="name">idea.category.form</field>
|
||||
<field name="model">idea.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Category of Ideas" version="7.0">
|
||||
<group>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Idea Category Tree View -->
|
||||
<record model="ir.ui.view" id="view_idea_category_tree">
|
||||
<field name="name">idea.category.tree</field>
|
||||
<field name="model">idea.category</field>
|
||||
<field name="field_parent"></field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Category of ideas">
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Idea Category Action -->
|
||||
|
||||
<record model="ir.actions.act_window" id="action_idea_category">
|
||||
<field name="name">Categories</field>
|
||||
<field name="res_model">idea.category</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_idea_category_search"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Configuration" parent="base.menu_tools"
|
||||
id="base.menu_lunch_survey_root" sequence="20" />
|
||||
|
||||
<menuitem name="Ideas" parent="base.menu_lunch_survey_root" id="menu_ideas" sequence="3"/>
|
||||
|
||||
<menuitem name="Categories" parent="menu_ideas" id="menu_idea_category" action="action_idea_category" />
|
||||
|
||||
|
||||
<!-- New Idea Form View -->
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_idea_form">
|
||||
<field name="name">idea.idea.form</field>
|
||||
<field name="model">idea.idea</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Idea" version="7.0">
|
||||
<header>
|
||||
<button name="idea_open" string="Open" states="draft" class="oe_highlight"/>
|
||||
<button name="idea_close" string="Accept" states="open" class="oe_highlight"/>
|
||||
<button name="idea_cancel" string="Refuse" states="open" class="oe_highlight"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,open,close"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1><field name="name"/></h1>
|
||||
<label for="category_ids" class="oe_edit_only"/>
|
||||
<field name="category_ids" widget="many2many_tags"/>
|
||||
<label for="description"/><newline/>
|
||||
<field name="description"/>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- New Idea Tree View -->
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_idea_tree">
|
||||
<field name="name">idea.idea.tree</field>
|
||||
<field name="model">idea.idea</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree colors="blue:state == 'draft';black:state in ('open','close');gray:state == 'cancel'" string="Ideas">
|
||||
<field name="name"/>
|
||||
<field name="create_uid"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Search Idea -->
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_idea_search">
|
||||
<field name="name">idea.idea.search</field>
|
||||
<field name="model">idea.idea</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Ideas">
|
||||
<field name="name" string="Idea"/>
|
||||
<filter icon="terp-document-new" string="New" domain="[('state','=', 'draft')]" help="New Ideas"/>
|
||||
<filter icon="terp-camera_test" string="In Progress" domain="[('state','=', 'open')]" help="Open Ideas"/>
|
||||
<filter icon="terp-check" string="Accepted" domain="[('state','=','close')]" help="Accepted Ideas" />
|
||||
<field name="category_ids"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter icon="terp-personal" string="Creator" help="By Creators" context="{'group_by':'create_uid'}"/>
|
||||
<filter icon="terp-stock_symbol-selection" string="Category" help="By Idea Category" context="{'group_by':'category_ids'}"/>
|
||||
<filter icon="terp-stock_effects-object-colorize" string="Status" help="By States" context="{'group_by':'state'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_idea_idea">
|
||||
<field name="name">Ideas</field>
|
||||
<field name="res_model">idea.idea</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_idea_idea_search"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Ideas" parent="menu_ideas" id="menu_idea_idea" action="action_idea_idea" sequence="1"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,60 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="workflow" id="wkf_idea">
|
||||
<field name="name">idea.wkf</field>
|
||||
<field name="osv">idea.idea</field>
|
||||
<field name="on_create">True</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_draft">
|
||||
<field name="wkf_id" ref="wkf_idea" />
|
||||
<field name="flow_start">True</field>
|
||||
<field name="name">draft</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">idea_draft()</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_open">
|
||||
<field name="wkf_id" ref="wkf_idea" />
|
||||
<field name="name">open</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">idea_open()</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_close">
|
||||
<field name="wkf_id" ref="wkf_idea" />
|
||||
<field name="name">close</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">idea_close()</field>
|
||||
<field name="flow_stop">True</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.activity" id="act_cancel">
|
||||
<field name="wkf_id" ref="wkf_idea" />
|
||||
<field name="name">cancel</field>
|
||||
<field name="kind">function</field>
|
||||
<field name="action">idea_cancel()</field>
|
||||
<field name="flow_stop">True</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t1">
|
||||
<field name="act_from" ref="act_draft" />
|
||||
<field name="act_to" ref="act_open" />
|
||||
<field name="signal">idea_open</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t2">
|
||||
<field name="act_from" ref="act_open" />
|
||||
<field name="act_to" ref="act_close" />
|
||||
<field name="signal">idea_close</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t4">
|
||||
<field name="act_from" ref="act_open" />
|
||||
<field name="act_to" ref="act_cancel" />
|
||||
<field name="signal">idea_cancel</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2013-TODAY OpenERP S.A. <http://openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import idea
|
|
@ -0,0 +1,130 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-Today OpenERP S.A. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv
|
||||
from openerp.osv import fields
|
||||
|
||||
|
||||
class IdeaCategory(osv.Model):
|
||||
""" Category of Idea """
|
||||
_name = "idea.category"
|
||||
_description = "Idea Category"
|
||||
|
||||
_order = 'name asc'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Category Name', size=64, required=True),
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('name', 'unique(name)', 'The name of the category must be unique')
|
||||
]
|
||||
|
||||
|
||||
class IdeaIdea(osv.Model):
|
||||
""" Model of an Idea """
|
||||
_name = 'idea.idea'
|
||||
_description = 'Propose and Share your Ideas'
|
||||
|
||||
_rec_name = 'name'
|
||||
_order = 'name asc'
|
||||
|
||||
def _get_state_list(self, cr, uid, context=None):
|
||||
return [('draft', 'New'),
|
||||
('open', 'In discussion'),
|
||||
('close', 'Accepted'),
|
||||
('cancel', 'Refused')]
|
||||
|
||||
def _get_color(self, cr, uid, ids, fields, args, context=None):
|
||||
res = dict.fromkeys(ids, 3)
|
||||
for idea in self.browse(cr, uid, ids, context=context):
|
||||
if idea.priority == 'low':
|
||||
res[idea.id] = 0
|
||||
elif idea.priority == 'high':
|
||||
res[idea.id] = 7
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'user_id': fields.many2one('res.users', 'Responsible', required=True),
|
||||
'name': fields.char('Summary', required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
oldname='title'),
|
||||
'description': fields.text('Description', required=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
help='Content of the idea'),
|
||||
'category_ids': fields.many2many('idea.category', string='Tags'),
|
||||
'state': fields.selection(_get_state_list, string='Status', required=True),
|
||||
'priority': fields.selection([('low', 'Low'), ('normal', 'Normal'), ('high', 'High')],
|
||||
string='Priority', required=True),
|
||||
'color': fields.function(_get_color, type='integer', string='Color Index'),
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('name', 'unique(name)', 'The name of the idea must be unique')
|
||||
]
|
||||
|
||||
_defaults = {
|
||||
'user_id': lambda self, cr, uid, ctx=None: uid,
|
||||
'state': lambda self, cr, uid, ctx=None: self._get_state_list(cr, uid, ctx)[0][0],
|
||||
'priority': 'normal',
|
||||
}
|
||||
|
||||
#------------------------------------------------------
|
||||
# Technical stuff
|
||||
#------------------------------------------------------
|
||||
|
||||
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
|
||||
""" Override read_group to always display all states. """
|
||||
if groupby and groupby[0] == "state":
|
||||
# Default result structure
|
||||
states = self._get_state_list(cr, uid, context=context)
|
||||
read_group_all_states = [{
|
||||
'__context': {'group_by': groupby[1:]},
|
||||
'__domain': domain + [('state', '=', state_value)],
|
||||
'state': state_value,
|
||||
'state_count': 0,
|
||||
} for state_value, state_name in states]
|
||||
# Get standard results
|
||||
read_group_res = super(IdeaIdea, self).read_group(cr, uid, domain, fields, groupby, offset, limit, context, orderby)
|
||||
# Update standard results with default results
|
||||
result = []
|
||||
for state_value, state_name in states:
|
||||
res = filter(lambda x: x['state'] == state_value, read_group_res)
|
||||
if not res:
|
||||
res = filter(lambda x: x['state'] == state_value, read_group_all_states)
|
||||
res[0]['state'] = [state_value, state_name]
|
||||
result.append(res[0])
|
||||
return result
|
||||
else:
|
||||
return super(IdeaIdea, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
|
||||
|
||||
#------------------------------------------------------
|
||||
# Workflow / Actions
|
||||
#------------------------------------------------------
|
||||
|
||||
def idea_set_low_priority(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'priority': 'low'}, context=context)
|
||||
|
||||
def idea_set_normal_priority(self, cr, uid, ids, context={}):
|
||||
return self.write(cr, uid, ids, {'priority': 'normal'}, context=context)
|
||||
|
||||
def idea_set_high_priority(self, cr, uid, ids, context={}):
|
||||
return self.write(cr, uid, ids, {'priority': 'high'}, context=context)
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="res.groups" id="base.group_tool_user">
|
||||
<field name="name">User</field>
|
||||
<field name="category_id" ref="base.module_category_tools"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_idea_category_user,idea.category user,model_idea_category,base.group_tool_user,1,1,1,1
|
||||
access_idea_idea_user,idea.idea user,model_idea_idea,base.group_tool_user,1,1,1,1
|
||||
access_idea_category_user,idea.category.user,model_idea_category,base.group_user,1,1,1,1
|
||||
access_idea_idea_user,idea.idea.user,model_idea_idea,base.group_user,1,1,1,1
|
||||
|
|
|
|
@ -0,0 +1,21 @@
|
|||
.openerp .oe_kanban_view .oe_kanban_idea_idea {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_view .oe_kanban_idea_idea .oe_avatars {
|
||||
text-align: right;
|
||||
margin: -5px 0 -10px 0;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_view .oe_kanban_idea_idea .oe_avatars img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding-left: 0px;
|
||||
margin-top: 3px;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||
-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 139 KiB |
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2013-TODAY OpenERP S.A. <http://openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -19,21 +19,10 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.addons.idea.tests import test_idea
|
||||
|
||||
class event_event(osv.osv):
|
||||
_description = 'Portal event'
|
||||
_inherit = 'event.event'
|
||||
checks = [
|
||||
test_idea,
|
||||
]
|
||||
|
||||
"""
|
||||
``visibility``: defines if the event appears on the portal's event page
|
||||
- 'public' means the event will appear for everyone (anonymous)
|
||||
- 'private' means the event won't appear
|
||||
"""
|
||||
_columns = {
|
||||
'visibility': fields.selection([('public', 'Public'),('private', 'Private')],
|
||||
string='Visibility', help='Event\'s visibility in the portal\'s contact page'),
|
||||
}
|
||||
_defaults = {
|
||||
'visibility': 'private',
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2013-TODAY OpenERP S.A. <http://openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.tests import common
|
||||
|
||||
|
||||
class TestIdeaBase(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestIdeaBase, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Usefull models
|
||||
self.idea_category = self.registry('idea.category')
|
||||
self.idea_idea = self.registry('idea.idea')
|
||||
|
||||
def tearDown(self):
|
||||
super(TestIdeaBase, self).tearDown()
|
||||
|
||||
def test_OO(self):
|
||||
pass
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- VIEWS DEFINITION
|
||||
-->
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_category_search">
|
||||
<field name="name">idea.category.search</field>
|
||||
<field name="model">idea.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Ideas Categories">
|
||||
<field name="name" string="Category"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_category_form">
|
||||
<field name="name">idea.category.form</field>
|
||||
<field name="model">idea.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Category of Ideas" version="7.0">
|
||||
<group>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_category_tree">
|
||||
<field name="name">idea.category.tree</field>
|
||||
<field name="model">idea.category</field>
|
||||
<field name="field_parent"></field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Category of ideas">
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_idea_category">
|
||||
<field name="name">Categories</field>
|
||||
<field name="res_model">idea.category</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_idea_category_search"/>
|
||||
</record>
|
||||
|
||||
<!-- MENUS
|
||||
-->
|
||||
|
||||
<menuitem name="Idea Tags" parent="mail.mail_my_stuff"
|
||||
id="menu_idea_category" action="action_idea_category" sequence="31"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,118 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_idea_kanban">
|
||||
<field name="name">idea.idea.kanban</field>
|
||||
<field name="model">idea.idea</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban version="7.0" default_group_by="state" class="oe_background_grey">
|
||||
<field name="color"/>
|
||||
<field name="user_id"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_kanban_card oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_idea_idea oe_kanban_global_click">
|
||||
<div class="oe_dropdown_toggle oe_dropdown_kanban"
|
||||
groups="base.group_user">
|
||||
<span class="oe_e">í</span>
|
||||
<ul class="oe_dropdown_menu">
|
||||
<t t-if="widget.view.is_action_enabled('delete')">
|
||||
<li><a type="delete">Delete</a></li>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oe_kanban_content">
|
||||
<h4><field name="name"/></h4>
|
||||
<div class="oe_kanban_bottom_right">
|
||||
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar" t-if="record.user_id.value"/>
|
||||
</div>
|
||||
<field name="category_ids"/>
|
||||
</div>
|
||||
<div class="oe_clear"></div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_idea_form">
|
||||
<field name="name">idea.idea.form</field>
|
||||
<field name="model">idea.idea</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Idea" version="7.0">
|
||||
<header>
|
||||
<button name="idea_set_low_priority" string="Set Low Priority" class="oe_highlight"
|
||||
attrs="{'invisible': [('priority', '!=', 'normal')]}"/>
|
||||
<button name="idea_set_normal_priority" string="Set Normal Priority" class="oe_highlight"
|
||||
attrs="{'invisible': [('priority', 'not in', ['low', 'high'])]}"/>
|
||||
<button name="idea_set_high_priority" string="Set High Priority" class="oe_highlight"
|
||||
attrs="{'invisible': [('priority', '!=', 'normal')]}"/>
|
||||
<field name="state" widget="statusbar" clickable="True"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1><field name="name"/></h1>
|
||||
<group>
|
||||
<field name="user_id"/>
|
||||
<field name="priority" readonly="True"/>
|
||||
<field name="category_ids" widget="many2many_tags"/>
|
||||
<field name="description"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_idea_tree">
|
||||
<field name="name">idea.idea.tree</field>
|
||||
<field name="model">idea.idea</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree colors="blue:state == 'draft';black:state in ('open', 'close'); gray:state == 'cancel'" string="Ideas">
|
||||
<field name="name"/>
|
||||
<field name="user_id"/>
|
||||
<field name="priority"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_idea_idea_search">
|
||||
<field name="name">idea.idea.search</field>
|
||||
<field name="model">idea.idea</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Ideas">
|
||||
<field name="name"/>
|
||||
<field name="user_id"/>
|
||||
<field name="category_ids"/>
|
||||
<filter string="New" domain="[('state', '=', 'draft')]"
|
||||
help="New Ideas"/>
|
||||
<filter string="In Progress" domain="[('state','=', 'open')]"
|
||||
help="Open Ideas"/>
|
||||
<filter string="Accepted" domain="[('state','=', 'close')]"
|
||||
help="Accepted Ideas" />
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Creator" help="By Responsible" context="{'group_by': 'user_id'}"/>
|
||||
<filter string="Category" help="By Category" context="{'group_by': 'category_ids'}"/>
|
||||
<filter string="Status" help="By State" context="{'group_by': 'state'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_idea_idea">
|
||||
<field name="name">Ideas</field>
|
||||
<field name="res_model">idea.idea</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="search_view_id" ref="view_idea_idea_search"/>
|
||||
</record>
|
||||
|
||||
<!-- MENUS
|
||||
-->
|
||||
|
||||
<menuitem name="Ideas" parent="mail.mail_my_stuff"
|
||||
id="menu_idea_idea" action="action_idea_idea" sequence="30"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -22,6 +22,8 @@
|
|||
import openerp
|
||||
import openerp.tools.config
|
||||
import openerp.modules.registry
|
||||
import openerp.addons.web.http as http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
import datetime
|
||||
from openerp.osv import osv, fields
|
||||
|
@ -90,36 +92,38 @@ POLL_TIMER = 30
|
|||
DISCONNECTION_TIMER = POLL_TIMER + 5
|
||||
WATCHER_ERROR_DELAY = 10
|
||||
|
||||
class LongPollingController(openerp.addons.web.http.Controller):
|
||||
_cp_path = '/longpolling/im'
|
||||
class LongPollingController(http.Controller):
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def poll(self, req, last=None, users_watch=None, db=None, uid=None, password=None, uuid=None):
|
||||
@http.route('/longpolling/im/poll', type="json", auth="none")
|
||||
def poll(self, last=None, users_watch=None, db=None, uid=None, password=None, uuid=None):
|
||||
assert_uuid(uuid)
|
||||
if not openerp.evented:
|
||||
raise Exception("Not usable in a server not running gevent")
|
||||
from openerp.addons.im.watcher import ImWatcher
|
||||
if db is not None:
|
||||
req.session._db = db
|
||||
req.session._uid = uid
|
||||
req.session._password = password
|
||||
req.session.model('im.user').im_connect(uuid=uuid, context=req.context)
|
||||
my_id = req.session.model('im.user').get_by_user_id(uuid or req.session._uid, req.context)["id"]
|
||||
request.session.authenticate(db=db, uid=uid, password=password)
|
||||
else:
|
||||
request.session.authenticate(db=request.session._db, uid=request.session._uid, password=request.session._password)
|
||||
|
||||
with request.registry.cursor() as cr:
|
||||
request.registry.get('im.user').im_connect(cr, request.uid, uuid=uuid, context=request.context)
|
||||
my_id = request.registry.get('im.user').get_by_user_id(cr, request.uid, uuid or request.session._uid, request.context)["id"]
|
||||
num = 0
|
||||
while True:
|
||||
res = req.session.model('im.message').get_messages(last, users_watch, uuid=uuid, context=req.context)
|
||||
with request.registry.cursor() as cr:
|
||||
res = request.registry.get('im.message').get_messages(cr, request.uid, last, users_watch, uuid=uuid, context=request.context)
|
||||
if num >= 1 or len(res["res"]) > 0:
|
||||
return res
|
||||
last = res["last"]
|
||||
num += 1
|
||||
ImWatcher.get_watcher(res["dbname"]).stop(my_id, users_watch or [], POLL_TIMER)
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def activated(self, req):
|
||||
@http.route('/longpolling/im/activated', type="json", auth="none")
|
||||
def activated(self):
|
||||
return not not openerp.evented
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def gen_uuid(self, req):
|
||||
@http.route('/longpolling/im/gen_uuid', type="json", auth="none")
|
||||
def gen_uuid(self):
|
||||
import uuid
|
||||
return "%s" % uuid.uuid1()
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ import random
|
|||
import jinja2
|
||||
from openerp.osv import osv, fields
|
||||
from openerp import tools
|
||||
import openerp.addons.web.http as http
|
||||
from openerp.addons.web.http import request
|
||||
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.PackageLoader('openerp.addons.im_livechat', "."),
|
||||
|
@ -33,48 +35,38 @@ env = jinja2.Environment(
|
|||
)
|
||||
env.filters["json"] = json.dumps
|
||||
|
||||
class LiveChatController(openerp.addons.web.http.Controller):
|
||||
_cp_path = '/im_livechat'
|
||||
class LiveChatController(http.Controller):
|
||||
|
||||
@openerp.addons.web.http.httprequest
|
||||
def loader(self, req, **kwargs):
|
||||
@http.route('/im_livechat/loader')
|
||||
def loader(self, **kwargs):
|
||||
p = json.loads(kwargs["p"])
|
||||
db = p["db"]
|
||||
channel = p["channel"]
|
||||
user_name = p.get("user_name", None)
|
||||
req.session._db = db
|
||||
req.session._uid = None
|
||||
req.session._login = "anonymous"
|
||||
req.session._password = "anonymous"
|
||||
info = req.session.model('im_livechat.channel').get_info_for_chat_src(channel)
|
||||
request.session.authenticate(db=db, login="anonymous", password="anonymous")
|
||||
info = request.session.model('im_livechat.channel').get_info_for_chat_src(channel)
|
||||
info["db"] = db
|
||||
info["channel"] = channel
|
||||
info["userName"] = user_name
|
||||
return req.make_response(env.get_template("loader.js").render(info),
|
||||
return request.make_response(env.get_template("loader.js").render(info),
|
||||
headers=[('Content-Type', "text/javascript")])
|
||||
|
||||
@openerp.addons.web.http.httprequest
|
||||
def web_page(self, req, **kwargs):
|
||||
@http.route('/im_livechat/web_page')
|
||||
def web_page(self, **kwargs):
|
||||
p = json.loads(kwargs["p"])
|
||||
db = p["db"]
|
||||
channel = p["channel"]
|
||||
req.session._db = db
|
||||
req.session._uid = None
|
||||
req.session._login = "anonymous"
|
||||
req.session._password = "anonymous"
|
||||
script = req.session.model('im_livechat.channel').read(channel, ["script"])["script"]
|
||||
info = req.session.model('im_livechat.channel').get_info_for_chat_src(channel)
|
||||
request.session.authenticate(db=db, login="anonymous", password="anonymous")
|
||||
script = request.session.model('im_livechat.channel').read(channel, ["script"])["script"]
|
||||
info = request.session.model('im_livechat.channel').get_info_for_chat_src(channel)
|
||||
info["script"] = script
|
||||
return req.make_response(env.get_template("web_page.html").render(info),
|
||||
return request.make_response(env.get_template("web_page.html").render(info),
|
||||
headers=[('Content-Type', "text/html")])
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def available(self, req, db, channel):
|
||||
req.session._db = db
|
||||
req.session._uid = None
|
||||
req.session._login = "anonymous"
|
||||
req.session._password = "anonymous"
|
||||
return req.session.model('im_livechat.channel').get_available_user(channel) > 0
|
||||
@http.route('/im_livechat/available', type='json')
|
||||
def available(self, db, channel):
|
||||
request.session.authenticate(db=db, login="anonymous", password="anonymous")
|
||||
return request.session.model('im_livechat.channel').get_available_user(channel) > 0
|
||||
|
||||
class im_livechat_channel(osv.osv):
|
||||
_name = 'im_livechat.channel'
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
# Thai translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-06-21 18:52+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Thai <th@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-22 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: knowledge
|
||||
#: view:knowledge.config.settings:0
|
||||
msgid "Documents"
|
||||
msgstr "เอกสาร"
|
||||
|
||||
#. module: knowledge
|
||||
#: model:ir.model,name:knowledge.model_knowledge_config_settings
|
||||
msgid "knowledge.config.settings"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: help:knowledge.config.settings,module_document_webdav:0
|
||||
msgid ""
|
||||
"Access your documents in OpenERP through WebDAV.\n"
|
||||
" This installs the module document_webdav."
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: help:knowledge.config.settings,module_document_page:0
|
||||
msgid "This installs the module document_page."
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: model:ir.ui.menu,name:knowledge.menu_document2
|
||||
msgid "Collaborative Content"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: model:ir.actions.act_window,name:knowledge.action_knowledge_configuration
|
||||
#: view:knowledge.config.settings:0
|
||||
msgid "Configure Knowledge"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: view:knowledge.config.settings:0
|
||||
msgid "Knowledge and Documents Management"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: help:knowledge.config.settings,module_document:0
|
||||
msgid ""
|
||||
"This is a complete document management system, with: user authentication,\n"
|
||||
" full document search (but pptx and docx are not supported), "
|
||||
"and a document dashboard.\n"
|
||||
" This installs the module document."
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: field:knowledge.config.settings,module_document_page:0
|
||||
msgid "Create static web pages"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: field:knowledge.config.settings,module_document_ftp:0
|
||||
msgid "Share repositories (FTP)"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: field:knowledge.config.settings,module_document:0
|
||||
msgid "Manage documents"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: view:knowledge.config.settings:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: view:knowledge.config.settings:0
|
||||
msgid "Apply"
|
||||
msgstr "ปรับใช้"
|
||||
|
||||
#. module: knowledge
|
||||
#: model:ir.ui.menu,name:knowledge.menu_document_configuration
|
||||
msgid "Configuration"
|
||||
msgstr "ตั้งค่า"
|
||||
|
||||
#. module: knowledge
|
||||
#: help:knowledge.config.settings,module_document_ftp:0
|
||||
msgid ""
|
||||
"Access your documents in OpenERP through an FTP interface.\n"
|
||||
" This installs the module document_ftp."
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: view:knowledge.config.settings:0
|
||||
msgid "or"
|
||||
msgstr "หรือ"
|
||||
|
||||
#. module: knowledge
|
||||
#: field:knowledge.config.settings,module_document_webdav:0
|
||||
msgid "Share repositories (WebDAV)"
|
||||
msgstr ""
|
||||
|
||||
#. module: knowledge
|
||||
#: model:ir.ui.menu,name:knowledge.menu_document
|
||||
#: model:ir.ui.menu,name:knowledge.menu_knowledge_configuration
|
||||
msgid "Knowledge"
|
||||
msgstr "ความรู้"
|
|
@ -0,0 +1,148 @@
|
|||
# Chinese (Simplified) translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-11-24 02:53+0000\n"
|
||||
"PO-Revision-Date: 2013-06-23 05:44+0000\n"
|
||||
"Last-Translator: Calvin <mceiba@gmail.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-24 04:43+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: help:hr.employee,disabled_spouse_bool:0
|
||||
msgid "if recipient spouse is declared disabled by law"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: help:hr.employee,disabled_children_bool:0
|
||||
msgid "if recipient children is/are declared disabled by law"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,misc_onss_deduction:0
|
||||
msgid "Miscellaneous exempt ONSS "
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: model:ir.model,name:l10n_be_hr_payroll.model_hr_employee
|
||||
msgid "Employee"
|
||||
msgstr "员工"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.employee,disabled_spouse_bool:0
|
||||
msgid "Disabled Spouse"
|
||||
msgstr "残疾人配偶"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,retained_net_amount:0
|
||||
msgid "Net retained "
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.employee,resident_bool:0
|
||||
msgid "Nonresident"
|
||||
msgstr "非常住人口"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: help:hr.employee,resident_bool:0
|
||||
msgid "if recipient lives in a foreign country"
|
||||
msgstr "如果接受者居住在国外"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: view:hr.employee:0
|
||||
msgid "if spouse has professionnel income or not"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,insurance_employee_deduction:0
|
||||
msgid "Insurance Group - by worker "
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: selection:hr.employee,spouse_fiscal_status:0
|
||||
msgid "With Income"
|
||||
msgstr "有收入"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: selection:hr.employee,spouse_fiscal_status:0
|
||||
msgid "Without Income"
|
||||
msgstr "无收入"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.employee,disabled_children_number:0
|
||||
msgid "Number of disabled children"
|
||||
msgstr "残疾儿童个数"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,additional_net_amount:0
|
||||
msgid "Net supplements"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,car_company_amount:0
|
||||
msgid "Company car employer"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,misc_advantage_amount:0
|
||||
msgid "Benefits of various nature "
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,car_employee_deduction:0
|
||||
msgid "Company Car Deduction for Worker"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.employee,disabled_children_bool:0
|
||||
msgid "Disabled Children"
|
||||
msgstr "残疾儿童"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: model:ir.model,name:l10n_be_hr_payroll.model_hr_contract
|
||||
msgid "Contract"
|
||||
msgstr "合约"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,meal_voucher_amount:0
|
||||
msgid "Check Value Meal "
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,travel_reimbursement_amount:0
|
||||
msgid "Reimbursement of travel expenses"
|
||||
msgstr "差旅花费补贴"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: constraint:hr.contract:0
|
||||
msgid "Error! Contract start-date must be less than contract end-date."
|
||||
msgstr "错误!联系人开始日期必须小于结束日期"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.employee,spouse_fiscal_status:0
|
||||
msgid "Tax status for spouse"
|
||||
msgstr "配偶缴税状态"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: view:hr.employee:0
|
||||
msgid "number of dependent children declared as disabled"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: constraint:hr.employee:0
|
||||
msgid "Error! You cannot create recursive hierarchy of Employee(s)."
|
||||
msgstr "错误!,你不能创建循环的员工层次"
|
||||
|
||||
#. module: l10n_be_hr_payroll
|
||||
#: field:hr.contract,meal_voucher_employee_deduction:0
|
||||
msgid "Check Value Meal - by worker "
|
||||
msgstr ""
|
File diff suppressed because it is too large
Load Diff
|
@ -39,6 +39,7 @@ def remove_accents(input_str):
|
|||
nkfd_form = unicodedata.normalize('NFKD', input_str)
|
||||
return u''.join([c for c in nkfd_form if not unicodedata.combining(c)])
|
||||
|
||||
|
||||
class mail_alias(osv.Model):
|
||||
"""A Mail Alias is a mapping of an email address with a given OpenERP Document
|
||||
model. It is used by OpenERP's mail gateway when processing incoming emails
|
||||
|
@ -47,7 +48,7 @@ class mail_alias(osv.Model):
|
|||
of that alias. If the message is a reply it will be attached to the
|
||||
existing discussion on the corresponding record, otherwise a new
|
||||
record of the corresponding model will be created.
|
||||
|
||||
|
||||
This is meant to be used in combination with a catch-all email configuration
|
||||
on the company's mail server, so that as soon as a new mail.alias is
|
||||
created, it becomes immediately usable and OpenERP will accept email for it.
|
||||
|
@ -63,9 +64,8 @@ class mail_alias(osv.Model):
|
|||
return dict.fromkeys(ids, domain or "")
|
||||
|
||||
_columns = {
|
||||
'alias_name': fields.char('Alias', required=True,
|
||||
help="The name of the email alias, e.g. 'jobs' "
|
||||
"if you want to catch emails for <jobs@example.my.openerp.com>",),
|
||||
'alias_name': fields.char('Alias',
|
||||
help="The name of the email alias, e.g. 'jobs' if you want to catch emails for <jobs@example.my.openerp.com>",),
|
||||
'alias_model_id': fields.many2one('ir.model', 'Aliased Model', required=True, ondelete="cascade",
|
||||
help="The model (OpenERP Document Kind) to which this alias "
|
||||
"corresponds. Any incoming email that does not reply to an "
|
||||
|
@ -87,13 +87,29 @@ class mail_alias(osv.Model):
|
|||
"messages will be attached, even if they did not reply to it. "
|
||||
"If set, this will disable the creation of new records completely."),
|
||||
'alias_domain': fields.function(_get_alias_domain, string="Alias domain", type='char', size=None),
|
||||
'alias_parent_model_id': fields.many2one('ir.model', 'Parent Model',
|
||||
help="Parent model holding the alias. The model holding the alias reference\n"
|
||||
"is not necessarily the model given by alias_model_id\n"
|
||||
"(example: project (parent_model) and task (model))"),
|
||||
'alias_parent_thread_id': fields.integer('Parent Record Thread ID',
|
||||
help="ID of the parent record holding the alias (example: project holding the task creation alias)"),
|
||||
'alias_contact': fields.selection([
|
||||
('everyone', 'Everyone'),
|
||||
('partners', 'Authenticated Partners'),
|
||||
('followers', 'Followers only'),
|
||||
], string='Alias Contact Security', required=True,
|
||||
help="Policy to post a message on the document using the mailgateway.\n"
|
||||
"- everyone: everyone can post\n"
|
||||
"- partners: only authenticated partners\n"
|
||||
"- followers: only followers of the related document\n"),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'alias_defaults': '{}',
|
||||
'alias_user_id': lambda self,cr,uid,context: uid,
|
||||
'alias_user_id': lambda self, cr, uid, context: uid,
|
||||
# looks better when creating new aliases - even if the field is informative only
|
||||
'alias_domain': lambda self,cr,uid,context: self._get_alias_domain(cr, SUPERUSER_ID,[1],None,None)[1]
|
||||
'alias_domain': lambda self, cr, uid, context: self._get_alias_domain(cr, SUPERUSER_ID, [1], None, None)[1],
|
||||
'alias_contact': 'everyone',
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
|
@ -139,13 +155,15 @@ class mail_alias(osv.Model):
|
|||
return new_name
|
||||
|
||||
def migrate_to_alias(self, cr, child_model_name, child_table_name, child_model_auto_init_fct,
|
||||
alias_id_column, alias_key, alias_prefix='', alias_force_key='', alias_defaults={}, context=None):
|
||||
alias_model_name, alias_id_column, alias_key, alias_prefix='', alias_force_key='', alias_defaults={},
|
||||
alias_generate_name=False, context=None):
|
||||
""" Installation hook to create aliases for all users and avoid constraint errors.
|
||||
|
||||
:param child_model_name: model name of the child class (i.e. res.users)
|
||||
:param child_table_name: table name of the child class (i.e. res_users)
|
||||
:param child_model_auto_init_fct: pointer to the _auto_init function
|
||||
(i.e. super(res_users,self)._auto_init(cr, context=context))
|
||||
:param alias_model_name: name of the aliased model
|
||||
:param alias_id_column: alias_id column (i.e. self._columns['alias_id'])
|
||||
:param alias_key: name of the column used for the unique name (i.e. 'login')
|
||||
:param alias_prefix: prefix for the unique name (i.e. 'jobs' + ...)
|
||||
|
@ -153,6 +171,8 @@ class mail_alias(osv.Model):
|
|||
if empty string, not taken into account
|
||||
:param alias_defaults: dict, keys = mail.alias columns, values = child
|
||||
model column name used for default values (i.e. {'job_id': 'id'})
|
||||
:param alias_generate_name: automatically generate alias name using prefix / alias key;
|
||||
default alias_name value is False because since 8.0 it is not required anymore
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
@ -170,13 +190,17 @@ class mail_alias(osv.Model):
|
|||
no_alias_ids = child_class_model.search(cr, SUPERUSER_ID, [('alias_id', '=', False)], context={'active_test': False})
|
||||
# Use read() not browse(), to avoid prefetching uninitialized inherited fields
|
||||
for obj_data in child_class_model.read(cr, SUPERUSER_ID, no_alias_ids, [alias_key]):
|
||||
alias_vals = {'alias_name': '%s%s' % (alias_prefix, obj_data[alias_key])}
|
||||
alias_vals = {'alias_name': False}
|
||||
if alias_generate_name:
|
||||
alias_vals['alias_name'] = '%s%s' % (alias_prefix, obj_data[alias_key])
|
||||
if alias_force_key:
|
||||
alias_vals['alias_force_thread_id'] = obj_data[alias_force_key]
|
||||
alias_vals['alias_defaults'] = dict((k, obj_data[v]) for k, v in alias_defaults.iteritems())
|
||||
alias_id = mail_alias.create_unique_alias(cr, SUPERUSER_ID, alias_vals, model_name=context.get('alias_model_name', child_model_name))
|
||||
alias_vals['alias_parent_thread_id'] = obj_data['id']
|
||||
alias_create_ctx = dict(context, alias_model_name=alias_model_name, alias_parent_model_name=child_model_name)
|
||||
alias_id = mail_alias.create(cr, SUPERUSER_ID, alias_vals, context=alias_create_ctx)
|
||||
child_class_model.write(cr, SUPERUSER_ID, obj_data['id'], {'alias_id': alias_id})
|
||||
_logger.info('Mail alias created for %s %s (uid %s)', child_model_name, obj_data[alias_key], obj_data['id'])
|
||||
_logger.info('Mail alias created for %s %s (id %s)', child_model_name, obj_data[alias_key], obj_data['id'])
|
||||
|
||||
# Finally attempt to reinstate the missing constraint
|
||||
try:
|
||||
|
@ -189,22 +213,53 @@ class mail_alias(osv.Model):
|
|||
|
||||
# set back the unique alias_id constraint
|
||||
alias_id_column.required = True
|
||||
|
||||
return res
|
||||
|
||||
def create_unique_alias(self, cr, uid, vals, model_name=None, context=None):
|
||||
"""Creates an email.alias record according to the values provided in ``vals``,
|
||||
with 2 alterations: the ``alias_name`` value may be suffixed in order to
|
||||
make it unique (and certain unsafe characters replaced), and
|
||||
he ``alias_model_id`` value will set to the model ID of the ``model_name``
|
||||
value, if provided,
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
""" Creates an email.alias record according to the values provided in ``vals``,
|
||||
with 2 alterations: the ``alias_name`` value may be suffixed in order to
|
||||
make it unique (and certain unsafe characters replaced), and
|
||||
he ``alias_model_id`` value will set to the model ID of the ``model_name``
|
||||
context value, if provided.
|
||||
"""
|
||||
# when an alias name appears to already be an email, we keep the local part only
|
||||
alias_name = remove_accents(vals['alias_name']).lower().split('@')[0]
|
||||
alias_name = re.sub(r'[^\w+.]+', '-', alias_name)
|
||||
alias_name = self._find_unique(cr, uid, alias_name, context=context)
|
||||
vals['alias_name'] = alias_name
|
||||
if context is None:
|
||||
context = {}
|
||||
model_name = context.get('alias_model_name')
|
||||
parent_model_name = context.get('alias_parent_model_name')
|
||||
if vals.get('alias_name'):
|
||||
# when an alias name appears to already be an email, we keep the local part only
|
||||
alias_name = remove_accents(vals['alias_name']).lower().split('@')[0]
|
||||
alias_name = re.sub(r'[^\w+.]+', '-', alias_name)
|
||||
alias_name = self._find_unique(cr, uid, alias_name, context=context)
|
||||
vals['alias_name'] = alias_name
|
||||
if model_name:
|
||||
model_id = self.pool.get('ir.model').search(cr, uid, [('model', '=', model_name)], context=context)[0]
|
||||
vals['alias_model_id'] = model_id
|
||||
return self.create(cr, uid, vals, context=context)
|
||||
if parent_model_name:
|
||||
model_id = self.pool.get('ir.model').search(cr, uid, [('model', '=', parent_model_name)], context=context)[0]
|
||||
vals['alias_parent_model_id'] = model_id
|
||||
return super(mail_alias, self).create(cr, uid, vals, context=context)
|
||||
|
||||
def open_document(self, cr, uid, ids, context=None):
|
||||
alias = self.browse(cr, uid, ids, context=context)[0]
|
||||
if not alias.alias_model_id or not alias.alias_force_thread_id:
|
||||
return False
|
||||
return {
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': alias.alias_model_id.model,
|
||||
'res_id': alias.alias_force_thread_id,
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
||||
def open_parent_document(self, cr, uid, ids, context=None):
|
||||
alias = self.browse(cr, uid, ids, context=context)[0]
|
||||
if not alias.alias_parent_model_id or not alias.alias_parent_thread_id:
|
||||
return False
|
||||
return {
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': alias.alias_parent_model_id.model,
|
||||
'res_id': alias.alias_parent_thread_id,
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
|
|
@ -9,13 +9,23 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Alias" version="7.0">
|
||||
<sheet>
|
||||
<label for="alias_name" class="oe_edit_only"/>
|
||||
<h2><field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline"/></h2>
|
||||
<div class="oe_right oe_button_box">
|
||||
<button name="open_document" string="Open Document"
|
||||
type="object" class="oe_link"
|
||||
attrs="{'invisible': ['|', ('alias_model_id', '=', False), ('alias_force_thread_id', '=', 0)]}"/>
|
||||
<button name="open_parent_document" string="Open Parent Document"
|
||||
type="object" class="oe_link"
|
||||
attrs="{'invisible': ['|', ('alias_parent_model_id', '=', False), ('alias_parent_thread_id', '=', 0)]}"/>
|
||||
</div>
|
||||
<group>
|
||||
<field name="alias_model_id"/>
|
||||
<field name="alias_user_id"/>
|
||||
<field name="alias_force_thread_id"/>
|
||||
<field name="alias_defaults"/>
|
||||
<field name="alias_contact"/>
|
||||
<field name="alias_user_id"/>
|
||||
<field name="alias_parent_model_id"/>
|
||||
<field name="alias_parent_thread_id"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
|
@ -32,6 +42,7 @@
|
|||
<field name="alias_model_id"/>
|
||||
<field name="alias_user_id"/>
|
||||
<field name="alias_defaults"/>
|
||||
<field name="alias_contact"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -44,8 +55,13 @@
|
|||
<search string="Search Alias">
|
||||
<field name="alias_name"/>
|
||||
<field name="alias_model_id"/>
|
||||
<field name="alias_force_thread_id"/>
|
||||
<field name="alias_parent_model_id"/>
|
||||
<field name="alias_parent_thread_id"/>
|
||||
<separator/>
|
||||
<filter string="Active" name="active" domain="[('alias_name', '!=', False)]"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="User" name="User" icon="terp-personal" context="{'group_by':'alias_user_id'}"/>
|
||||
<filter string="User" name="User" context="{'group_by':'alias_user_id'}"/>
|
||||
<filter string="Model" name="Model" context="{'group_by':'alias_model_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
|
@ -55,6 +71,10 @@
|
|||
<record id="action_view_mail_alias" model="ir.actions.act_window">
|
||||
<field name="name">Aliases</field>
|
||||
<field name="res_model">mail.alias</field>
|
||||
<field name="context">{
|
||||
'search_default_active': True,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="mail_alias_menu"
|
||||
|
|
|
@ -93,17 +93,16 @@ class mail_group(osv.Model):
|
|||
'public': 'groups',
|
||||
'group_public_id': _get_default_employee_group,
|
||||
'image': _get_default_image,
|
||||
'alias_domain': False, # always hide alias during creation
|
||||
}
|
||||
|
||||
def _generate_header_description(self, cr, uid, group, context=None):
|
||||
header = ''
|
||||
if group.description:
|
||||
header = '%s' % group.description
|
||||
if group.alias_id and group.alias_id.alias_name and group.alias_id.alias_domain:
|
||||
if group.alias_id and group.alias_name and group.alias_domain:
|
||||
if header:
|
||||
header = '%s<br/>' % header
|
||||
return '%sGroup email gateway: %s@%s' % (header, group.alias_id.alias_name, group.alias_id.alias_domain)
|
||||
return '%sGroup email gateway: %s@%s' % (header, group.alias_name, group.alias_domain)
|
||||
return header
|
||||
|
||||
def _subscribe_users(self, cr, uid, ids, context=None):
|
||||
|
@ -114,15 +113,8 @@ class mail_group(osv.Model):
|
|||
self.message_subscribe(cr, uid, ids, partner_ids, context=context)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
mail_alias = self.pool.get('mail.alias')
|
||||
if not vals.get('alias_id'):
|
||||
vals.pop('alias_name', None) # prevent errors during copy()
|
||||
alias_id = mail_alias.create_unique_alias(cr, uid,
|
||||
# Using '+' allows using subaddressing for those who don't
|
||||
# have a catchall domain setup.
|
||||
{'alias_name': "group+" + vals['name']},
|
||||
model_name=self._name, context=context)
|
||||
vals['alias_id'] = alias_id
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
# get parent menu
|
||||
menu_parent = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'mail_group_root')
|
||||
|
@ -134,8 +126,10 @@ class mail_group(osv.Model):
|
|||
vals['menu_id'] = menu_id
|
||||
|
||||
# Create group and alias
|
||||
mail_group_id = super(mail_group, self).create(cr, uid, vals, context=context)
|
||||
mail_alias.write(cr, uid, [vals['alias_id']], {"alias_force_thread_id": mail_group_id}, context)
|
||||
create_context = dict(context, alias_model_name=self._name, alias_parent_model_name=self._name)
|
||||
mail_group_id = super(mail_group, self).create(cr, uid, vals, context=create_context)
|
||||
group = self.browse(cr, uid, mail_group_id, context=context)
|
||||
self.pool.get('mail.alias').write(cr, uid, [group.alias_id.id], {"alias_force_thread_id": mail_group_id, 'alias_parent_thread_id': mail_group_id}, context)
|
||||
group = self.browse(cr, uid, mail_group_id, context=context)
|
||||
|
||||
# Create client action for this group and link the menu to it
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
<div class="oe_group_details">
|
||||
<h4><a type="open"><field name="name"/></a></h4>
|
||||
<div class="oe_kanban_alias" t-if="record.alias_id.value">
|
||||
<span class="oe_e">%%</span><small><field name="alias_id"/></small>
|
||||
<span class="oe_e oe_e_alias">%%</span><small><field name="alias_id"/></small>
|
||||
</div>
|
||||
<div class="oe_grey">
|
||||
<field name="description"/>
|
||||
|
@ -78,17 +78,19 @@
|
|||
<label for="name" string="Group Name"/>
|
||||
</div>
|
||||
<h1><field name="name" readonly="0"/></h1>
|
||||
<div name="group_alias"
|
||||
<group colspan="2" name="group_alias"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}">
|
||||
<label for="alias_id" string="Email Alias"/>
|
||||
<field name="alias_id" class="oe_inline oe_read_only" required="0" nolabel="1"/>
|
||||
<span name="edit_alias" class="oe_edit_only">
|
||||
<field name="alias_name" class="oe_inline"
|
||||
attrs="{'required': [('alias_id', '!=', False)]}"/>
|
||||
@
|
||||
<field name="alias_domain" class="oe_inline" readonly="1"/>
|
||||
</span>
|
||||
</div>
|
||||
<label for="alias_id" string="%%" class="oe_e oe_e_alias" style="min-width: 20px;"/>
|
||||
<div name="alias_def">
|
||||
<field name="alias_id" class="oe_read_only oe_inline"
|
||||
string="Email Alias" required="0"/>
|
||||
<div class="oe_edit_only oe_inline" name="edit_alias" style="display: inline;" >
|
||||
<field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
|
||||
</div>
|
||||
</div>
|
||||
<label for="alias_contact" string="V" class="oe_e oe_e_alias" style="min-width: 20px;"/>
|
||||
<field name="alias_contact" class="oe_inline" nolabel="1"/>
|
||||
</group>
|
||||
</div>
|
||||
<field name="description" placeholder="Topics discussed in this group..."/>
|
||||
<div class="oe_clear"/>
|
||||
|
|
|
@ -25,7 +25,6 @@ import dateutil
|
|||
import email
|
||||
import logging
|
||||
import pytz
|
||||
import re
|
||||
import time
|
||||
import xmlrpclib
|
||||
from email.message import Message
|
||||
|
@ -102,21 +101,22 @@ class mail_thread(osv.AbstractModel):
|
|||
if catchall_domain and model and res_id: # specific res_id -> find its alias (i.e. section_id specified)
|
||||
object_id = self.pool.get(model).browse(cr, uid, res_id, context=context)
|
||||
# check that the alias effectively creates new records
|
||||
if object_id.alias_id and object_id.alias_id.alias_model_id and \
|
||||
if object_id.alias_id and object_id.alias_id.alias_name and \
|
||||
object_id.alias_id.alias_model_id and \
|
||||
object_id.alias_id.alias_model_id.model == self._name and \
|
||||
object_id.alias_id.alias_force_thread_id == 0:
|
||||
alias = object_id.alias_id
|
||||
elif catchall_domain and model: # no specific res_id given -> generic help message, take an example alias (i.e. alias of some section_id)
|
||||
model_id = self.pool.get('ir.model').search(cr, uid, [("model", "=", self._name)], context=context)[0]
|
||||
alias_obj = self.pool.get('mail.alias')
|
||||
alias_ids = alias_obj.search(cr, uid, [("alias_model_id", "=", model_id), ('alias_force_thread_id', '=', 0)], context=context, order='id ASC')
|
||||
alias_ids = alias_obj.search(cr, uid, [("alias_model_id", "=", model_id), ("alias_name", "!=", False), ('alias_force_thread_id', '=', 0)], context=context, order='id ASC')
|
||||
if alias_ids and len(alias_ids) == 1: # if several aliases -> incoherent to propose one guessed from nowhere, therefore avoid if several aliases
|
||||
alias = alias_obj.browse(cr, uid, alias_ids[0], context=context)
|
||||
|
||||
if alias:
|
||||
alias_email = alias.name_get()[0][1]
|
||||
return _("""<p class='oe_view_nocontent_create'>
|
||||
Click here to add a new %(document)s or send an email to: <a href='mailto:%(email)s'>%(email)s</a>
|
||||
Click here to add new %(document)s or send an email to: <a href='mailto:%(email)s'>%(email)s</a>
|
||||
</p>
|
||||
%(static_help)s"""
|
||||
) % {
|
||||
|
@ -126,7 +126,7 @@ class mail_thread(osv.AbstractModel):
|
|||
}
|
||||
|
||||
if document_name != 'document' and help and help.find("oe_view_nocontent_create") == -1:
|
||||
return _("<p class='oe_view_nocontent_create'>Click here to add a new %(document)s</p>%(static_help)s") % {
|
||||
return _("<p class='oe_view_nocontent_create'>Click here to add new %(document)s</p>%(static_help)s") % {
|
||||
'document': document_name,
|
||||
'static_help': help or '',
|
||||
}
|
||||
|
@ -257,7 +257,6 @@ class mail_thread(osv.AbstractModel):
|
|||
|
||||
def _search_is_follower(self, cr, uid, obj, name, args, context):
|
||||
"""Search function for message_is_follower"""
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
res = []
|
||||
for field, operator, value in args:
|
||||
assert field == name
|
||||
|
@ -564,6 +563,8 @@ class mail_thread(osv.AbstractModel):
|
|||
#------------------------------------------------------
|
||||
|
||||
def message_get_reply_to(self, cr, uid, ids, context=None):
|
||||
""" Returns the preferred reply-to email address that is basically
|
||||
the alias of the document, if it exists. """
|
||||
if not self._inherits.get('mail.alias'):
|
||||
return [False for id in ids]
|
||||
return ["%s@%s" % (record['alias_name'], record['alias_domain'])
|
||||
|
@ -587,27 +588,123 @@ class mail_thread(osv.AbstractModel):
|
|||
def _message_find_partners(self, cr, uid, message, header_fields=['From'], context=None):
|
||||
""" Find partners related to some header fields of the message.
|
||||
|
||||
TDE TODO: merge me with other partner finding methods in 8.0 """
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
partner_ids = []
|
||||
:param string message: an email.message instance """
|
||||
s = ', '.join([decode(message.get(h)) for h in header_fields if message.get(h)])
|
||||
for email_address in tools.email_split(s):
|
||||
related_partners = partner_obj.search(cr, uid, [('email', 'ilike', email_address), ('user_ids', '!=', False)], limit=1, context=context)
|
||||
if not related_partners:
|
||||
related_partners = partner_obj.search(cr, uid, [('email', 'ilike', email_address)], limit=1, context=context)
|
||||
partner_ids += related_partners
|
||||
return partner_ids
|
||||
return filter(lambda x: x, self._find_partner_from_emails(cr, uid, None, tools.email_split(s), context=context))
|
||||
|
||||
def _message_find_user_id(self, cr, uid, message, context=None):
|
||||
""" TDE TODO: check and maybe merge me with other user finding methods in 8.0 """
|
||||
from_local_part = tools.email_split(decode(message.get('From')))[0]
|
||||
# FP Note: canonification required, the minimu: .lower()
|
||||
user_ids = self.pool.get('res.users').search(cr, uid, ['|',
|
||||
('login', '=', from_local_part),
|
||||
('email', '=', from_local_part)], context=context)
|
||||
return user_ids[0] if user_ids else uid
|
||||
def message_route_verify(self, cr, uid, message, message_dict, route, update_author=True, assert_model=True, create_fallback=True, context=None):
|
||||
""" Verify route validity. Check and rules:
|
||||
1 - if thread_id -> check that document effectively exists; otherwise
|
||||
fallback on a message_new by resetting thread_id
|
||||
2 - check that message_update exists if thread_id is set; or at least
|
||||
that message_new exist
|
||||
[ - find author_id if udpate_author is set]
|
||||
3 - if there is an alias, check alias_contact:
|
||||
'followers' and thread_id:
|
||||
check on target document that the author is in the followers
|
||||
'followers' and alias_parent_thread_id:
|
||||
check on alias parent document that the author is in the
|
||||
followers
|
||||
'partners': check that author_id id set
|
||||
"""
|
||||
|
||||
def message_route(self, cr, uid, message, model=None, thread_id=None,
|
||||
assert isinstance(route, (list, tuple)), 'A route should be a list or a tuple'
|
||||
assert len(route) == 5, 'A route should contain 5 elements: model, thread_id, custom_values, uid, alias record'
|
||||
|
||||
message_id = message.get('Message-Id')
|
||||
email_from = decode_header(message, 'From')
|
||||
author_id = message_dict.get('author_id')
|
||||
model, thread_id, alias = route[0], route[1], route[4]
|
||||
model_pool = None
|
||||
|
||||
def _create_bounce_email():
|
||||
mail_mail = self.pool.get('mail.mail')
|
||||
mail_id = mail_mail.create(cr, uid, {
|
||||
'body_html': '<div><p>Hello,</p>'
|
||||
'<p>The following email sent to %s cannot be accepted because this is '
|
||||
'a private email address. Only allowed people can contact us at this address.</p></div>'
|
||||
'<blockquote>%s</blockquote>' % (message.get('to'), message_dict.get('body')),
|
||||
'subject': 'Re: %s' % message.get('subject'),
|
||||
'email_to': message.get('from'),
|
||||
'auto_delete': True,
|
||||
}, context=context)
|
||||
mail_mail.send(cr, uid, [mail_id], context=context)
|
||||
|
||||
def _warn(message):
|
||||
_logger.warning('Routing mail with Message-Id %s: route %s: %s',
|
||||
message_id, route, message)
|
||||
|
||||
# Wrong model
|
||||
if model and not model in self.pool:
|
||||
if assert_model:
|
||||
assert model in self.pool, 'Routing: unknown target model %s' % model
|
||||
_warn('unknown target model %s' % model)
|
||||
return ()
|
||||
elif model:
|
||||
model_pool = self.pool[model]
|
||||
|
||||
# Private message: should not contain any thread_id
|
||||
if not model and thread_id:
|
||||
if assert_model:
|
||||
assert thread_id == 0, 'Routing: posting a message without model should be with a null res_id (private message).'
|
||||
_warn('posting a message without model should be with a null res_id (private message), resetting thread_id')
|
||||
thread_id = 0
|
||||
|
||||
# Existing Document: check if exists; if not, fallback on create if allowed
|
||||
if thread_id and not model_pool.exists(cr, uid, thread_id):
|
||||
if create_fallback:
|
||||
_warn('reply to missing document (%s,%s), fall back on new document creation' % (model, thread_id))
|
||||
thread_id = None
|
||||
elif assert_model:
|
||||
assert model_pool.exists(cr, uid, thread_id), 'Routing: reply to missing document (%s,%s)' % (model, thread_id)
|
||||
else:
|
||||
_warn('reply to missing document (%s,%s), skipping' % (model, thread_id))
|
||||
return ()
|
||||
|
||||
# Existing Document: check model accepts the mailgateway
|
||||
if thread_id and not hasattr(model_pool, 'message_update'):
|
||||
if create_fallback:
|
||||
_warn('model %s does not accept document update, fall back on document creation' % model)
|
||||
thread_id = None
|
||||
elif assert_model:
|
||||
assert hasattr(model_pool, 'message_update'), 'Routing: model %s does not accept document update, crashing' % model
|
||||
else:
|
||||
_warn('model %s does not accept document update, skipping' % model)
|
||||
return ()
|
||||
|
||||
# New Document: check model accepts the mailgateway
|
||||
if not thread_id and not hasattr(model_pool, 'message_new'):
|
||||
if assert_model:
|
||||
assert hasattr(model_pool, 'message_new'), 'Model %s does not accept document creation, crashing' % model
|
||||
_warn('model %s does not accept document creation, skipping' % model)
|
||||
return ()
|
||||
|
||||
# Update message author if asked
|
||||
# We do it now because we need it for aliases (contact settings)
|
||||
if not author_id and update_author:
|
||||
author_ids = self._find_partner_from_emails(cr, uid, thread_id, [email_from], model=model, context=context)
|
||||
if author_ids:
|
||||
author_id = author_ids[0]
|
||||
message_dict['author_id'] = author_id
|
||||
|
||||
# Alias: check alias_contact settings
|
||||
if alias and alias.alias_contact == 'followers' and (thread_id or alias.alias_parent_thread_id):
|
||||
if thread_id:
|
||||
obj = self.pool[model].browse(cr, uid, thread_id, context=context)
|
||||
else:
|
||||
obj = self.pool[alias.alias_parent_model_id.model].browse(cr, uid, alias.alias_parent_thread_id, context=context)
|
||||
if not author_id or not author_id in [fol.id for fol in obj.message_follower_ids]:
|
||||
_warn('alias %s restricted to internal followers, skipping' % alias.alias_name)
|
||||
_create_bounce_email()
|
||||
return ()
|
||||
elif alias and alias.alias_contact == 'partners' and not author_id:
|
||||
_warn('alias %s does not accept unknown author, skipping' % alias.alias_name)
|
||||
_create_bounce_email()
|
||||
return ()
|
||||
|
||||
return (model, thread_id, route[2], route[3], route[4])
|
||||
|
||||
def message_route(self, cr, uid, message, message_dict, model=None, thread_id=None,
|
||||
custom_values=None, context=None):
|
||||
"""Attempt to figure out the correct target model, thread_id,
|
||||
custom_values and user_id to use for an incoming message.
|
||||
|
@ -627,6 +724,7 @@ class mail_thread(osv.AbstractModel):
|
|||
4. If all the above fails, raise an exception.
|
||||
|
||||
:param string message: an email.message instance
|
||||
:param dict message_dict: dictionary holding message variables
|
||||
:param string model: the fallback model to use if the message
|
||||
does not match any of the currently configured mail aliases
|
||||
(may be None if a matching alias is supposed to be present)
|
||||
|
@ -637,9 +735,12 @@ class mail_thread(osv.AbstractModel):
|
|||
:param int thread_id: optional ID of the record/thread from ``model``
|
||||
to which this mail should be attached. Only used if the message
|
||||
does not reply to an existing thread and does not match any mail alias.
|
||||
:return: list of [model, thread_id, custom_values, user_id]
|
||||
:return: list of [model, thread_id, custom_values, user_id, alias]
|
||||
"""
|
||||
assert isinstance(message, Message), 'message must be an email.message.Message at this point'
|
||||
fallback_model = model
|
||||
|
||||
# Get email.message.Message variables for future processing
|
||||
message_id = message.get('Message-Id')
|
||||
email_from = decode_header(message, 'From')
|
||||
email_to = decode_header(message, 'To')
|
||||
|
@ -649,18 +750,20 @@ class mail_thread(osv.AbstractModel):
|
|||
# 1. Verify if this is a reply to an existing thread
|
||||
thread_references = references or in_reply_to
|
||||
ref_match = thread_references and tools.reference_re.search(thread_references)
|
||||
|
||||
if ref_match:
|
||||
thread_id = int(ref_match.group(1))
|
||||
model = ref_match.group(2) or model
|
||||
model = ref_match.group(2) or fallback_model
|
||||
if thread_id and model in self.pool:
|
||||
model_obj = self.pool[model]
|
||||
if model_obj.exists(cr, uid, thread_id) and hasattr(model_obj, 'message_update'):
|
||||
_logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to model: %s, thread_id: %s, custom_values: %s, uid: %s',
|
||||
email_from, email_to, message_id, model, thread_id, custom_values, uid)
|
||||
return [(model, thread_id, custom_values, uid)]
|
||||
route = self.message_route_verify(cr, uid, message, message_dict,
|
||||
(model, thread_id, custom_values, uid, None),
|
||||
update_author=True, assert_model=True, create_fallback=True, context=context)
|
||||
return route and [route] or []
|
||||
|
||||
# Verify whether this is a reply to a private message
|
||||
# 2. Reply to a private message
|
||||
if in_reply_to:
|
||||
message_ids = self.pool.get('mail.message').search(cr, uid, [
|
||||
('message_id', '=', in_reply_to),
|
||||
|
@ -670,9 +773,12 @@ class mail_thread(osv.AbstractModel):
|
|||
message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context)
|
||||
_logger.info('Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
|
||||
email_from, email_to, message_id, message.id, custom_values, uid)
|
||||
return [(message.model, message.res_id, custom_values, uid)]
|
||||
route = self.message_route_verify(cr, uid, message, message_dict,
|
||||
(message.model, message.res_id, custom_values, uid, None),
|
||||
update_author=True, assert_model=True, create_fallback=True, context=context)
|
||||
return route and [route] or []
|
||||
|
||||
# 2. Look for a matching mail.alias entry
|
||||
# 3. Look for a matching mail.alias entry
|
||||
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
|
||||
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
|
||||
rcpt_tos = \
|
||||
|
@ -697,14 +803,16 @@ class mail_thread(osv.AbstractModel):
|
|||
# user_id = self._message_find_user_id(cr, uid, message, context=context)
|
||||
user_id = uid
|
||||
_logger.info('No matching user_id for the alias %s', alias.alias_name)
|
||||
routes.append((alias.alias_model_id.model, alias.alias_force_thread_id, \
|
||||
eval(alias.alias_defaults), user_id))
|
||||
_logger.info('Routing mail from %s to %s with Message-Id %s: direct alias match: %r',
|
||||
email_from, email_to, message_id, routes)
|
||||
route = (alias.alias_model_id.model, alias.alias_force_thread_id, eval(alias.alias_defaults), user_id, alias)
|
||||
_logger.info('Routing mail from %s to %s with Message-Id %s: direct alias match: %r',
|
||||
email_from, email_to, message_id, route)
|
||||
route = self.message_route_verify(cr, uid, message, message_dict, route,
|
||||
update_author=True, assert_model=True, create_fallback=True, context=context)
|
||||
if route:
|
||||
routes.append(route)
|
||||
return routes
|
||||
|
||||
# 3. Fallback to the provided parameters, if they work
|
||||
model_pool = self.pool.get(model)
|
||||
# 4. Fallback to the provided parameters, if they work
|
||||
if not thread_id:
|
||||
# Legacy: fallback to matching [ID] in the Subject
|
||||
match = tools.res_re.search(decode_header(message, 'Subject'))
|
||||
|
@ -714,16 +822,18 @@ class mail_thread(osv.AbstractModel):
|
|||
thread_id = int(thread_id)
|
||||
except:
|
||||
thread_id = False
|
||||
assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
|
||||
_logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s',
|
||||
email_from, email_to, message_id, fallback_model, thread_id, custom_values, uid)
|
||||
route = self.message_route_verify(cr, uid, message, message_dict,
|
||||
(fallback_model, thread_id, custom_values, uid, None),
|
||||
update_author=True, assert_model=True, context=context)
|
||||
if route:
|
||||
return [route]
|
||||
|
||||
# AssertionError if no routes found and if no bounce occured
|
||||
assert False, \
|
||||
"No possible route found for incoming message from %s to %s (Message-Id %s:)." \
|
||||
"Create an appropriate mail.alias or force the destination model." % (email_from, email_to, message_id)
|
||||
if thread_id and not model_pool.exists(cr, uid, thread_id):
|
||||
_logger.warning('Received mail reply to missing document %s! Ignoring and creating new document instead for Message-Id %s',
|
||||
thread_id, message_id)
|
||||
thread_id = None
|
||||
_logger.info('Routing mail from %s to %s with Message-Id %s: fallback to model:%s, thread_id:%s, custom_values:%s, uid:%s',
|
||||
email_from, email_to, message_id, model, thread_id, custom_values, uid)
|
||||
return [(model, thread_id, custom_values, uid)]
|
||||
|
||||
def message_process(self, cr, uid, model, message, custom_values=None,
|
||||
save_original=False, strip_attachments=False,
|
||||
|
@ -777,25 +887,21 @@ class mail_thread(osv.AbstractModel):
|
|||
msg = self.message_parse(cr, uid, msg_txt, save_original=save_original, context=context)
|
||||
if strip_attachments:
|
||||
msg.pop('attachments', None)
|
||||
# postpone setting msg.partner_ids after message_post, to avoid double notifications
|
||||
partner_ids = msg.pop('partner_ids', [])
|
||||
if msg.get('message_id'): # should always be True as message_parse generate one if missing
|
||||
existing_msg_ids = self.pool.get('mail.message').search(cr, SUPERUSER_ID, [
|
||||
('message_id', '=', msg.get('message_id')),
|
||||
], context=context)
|
||||
if existing_msg_ids:
|
||||
_logger.info('Ignored mail from %s to %s with Message-Id %s:: found duplicated Message-Id during processing',
|
||||
_logger.info('Ignored mail from %s to %s with Message-Id %s: found duplicated Message-Id during processing',
|
||||
msg.get('from'), msg.get('to'), msg.get('message_id'))
|
||||
return False
|
||||
|
||||
# find possible routes for the message
|
||||
routes = self.message_route(cr, uid, msg_txt, model,
|
||||
thread_id, custom_values,
|
||||
context=context)
|
||||
|
||||
# postpone setting msg.partner_ids after message_post, to avoid double notifications
|
||||
partner_ids = msg.pop('partner_ids', [])
|
||||
|
||||
routes = self.message_route(cr, uid, msg_txt, msg, model, thread_id, custom_values, context=context)
|
||||
thread_id = False
|
||||
for model, thread_id, custom_values, user_id in routes:
|
||||
for model, thread_id, custom_values, user_id, alias in routes:
|
||||
if self._name == 'mail.thread':
|
||||
context.update({'thread_model': model})
|
||||
if model:
|
||||
|
@ -806,11 +912,10 @@ class mail_thread(osv.AbstractModel):
|
|||
|
||||
# disabled subscriptions during message_new/update to avoid having the system user running the
|
||||
# email gateway become a follower of all inbound messages
|
||||
nosub_ctx = dict(context, mail_create_nosubscribe=True)
|
||||
nosub_ctx = dict(context, mail_create_nosubscribe=True, mail_create_nolog=True)
|
||||
if thread_id and hasattr(model_pool, 'message_update'):
|
||||
model_pool.message_update(cr, user_id, [thread_id], msg, context=nosub_ctx)
|
||||
else:
|
||||
nosub_ctx = dict(nosub_ctx, mail_create_nolog=True)
|
||||
thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=nosub_ctx)
|
||||
else:
|
||||
assert thread_id == 0, "Posting a message without model should be with a null res_id, to create a private message."
|
||||
|
@ -947,7 +1052,6 @@ class mail_thread(osv.AbstractModel):
|
|||
"""
|
||||
msg_dict = {
|
||||
'type': 'email',
|
||||
'author_id': False,
|
||||
}
|
||||
if not isinstance(message, Message):
|
||||
if isinstance(message, unicode):
|
||||
|
@ -970,12 +1074,7 @@ class mail_thread(osv.AbstractModel):
|
|||
msg_dict['from'] = decode(message.get('from'))
|
||||
msg_dict['to'] = decode(message.get('to'))
|
||||
msg_dict['cc'] = decode(message.get('cc'))
|
||||
|
||||
if message.get('From'):
|
||||
author_ids = self._message_find_partners(cr, uid, message, ['From'], context=context)
|
||||
if author_ids:
|
||||
msg_dict['author_id'] = author_ids[0]
|
||||
msg_dict['email_from'] = decode(message.get('from'))
|
||||
msg_dict['email_from'] = decode(message.get('from'))
|
||||
partner_ids = self._message_find_partners(cr, uid, message, ['To', 'Cc'], context=context)
|
||||
msg_dict['partner_ids'] = [(4, partner_id) for partner_id in partner_ids]
|
||||
|
||||
|
@ -1029,7 +1128,7 @@ class mail_thread(osv.AbstractModel):
|
|||
partner_id, partner_name<partner_email> or partner_name, reason """
|
||||
if email and not partner:
|
||||
# get partner info from email
|
||||
partner_info = self.message_get_partner_info_from_emails(cr, uid, [email], context=context, res_id=obj.id)[0]
|
||||
partner_info = self.message_partner_info_from_emails(cr, uid, obj.id, [email], context=context)[0]
|
||||
if partner_info.get('partner_id'):
|
||||
partner = self.pool.get('res.partner').browse(cr, SUPERUSER_ID, [partner_info.get('partner_id')], context=context)[0]
|
||||
if email and email in [val[1] for val in result[obj.id]]: # already existing email -> skip
|
||||
|
@ -1057,53 +1156,76 @@ class mail_thread(osv.AbstractModel):
|
|||
self._message_add_suggested_recipient(cr, uid, result, obj, partner=obj.user_id.partner_id, reason=self._all_columns['user_id'].column.string, context=context)
|
||||
return result
|
||||
|
||||
def message_get_partner_info_from_emails(self, cr, uid, emails, link_mail=False, context=None, res_id=None):
|
||||
""" Wrapper with weird order parameter because of 7.0 fix.
|
||||
def _find_partner_from_emails(self, cr, uid, id, emails, model=None, context=None, check_followers=True):
|
||||
""" Utility method to find partners from email addresses. The rules are :
|
||||
1 - check in document (model | self, id) followers
|
||||
2 - try to find a matching partner that is also an user
|
||||
3 - try to find a matching partner
|
||||
|
||||
TDE TODO: remove me in 8.0 """
|
||||
return self.message_find_partner_from_emails(cr, uid, res_id, emails, link_mail=link_mail, context=context)
|
||||
|
||||
def message_find_partner_from_emails(self, cr, uid, id, emails, link_mail=False, context=None):
|
||||
""" Convert a list of emails into a list partner_ids and a list
|
||||
new_partner_ids. The return value is non conventional because
|
||||
it is meant to be used by the mail widget.
|
||||
|
||||
:return dict: partner_ids and new_partner_ids
|
||||
|
||||
TDE TODO: merge me with other partner finding methods in 8.0 """
|
||||
mail_message_obj = self.pool.get('mail.message')
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
result = list()
|
||||
if id and self._name != 'mail.thread':
|
||||
obj = self.browse(cr, SUPERUSER_ID, id, context=context)
|
||||
else:
|
||||
obj = None
|
||||
for email in emails:
|
||||
partner_info = {'full_name': email, 'partner_id': False}
|
||||
m = re.search(r"((.+?)\s*<)?([^<>]+@[^<>]+)>?", email, re.IGNORECASE | re.DOTALL)
|
||||
if not m:
|
||||
:param list emails: list of email addresses
|
||||
:param string model: model to fetch related record; by default self
|
||||
is used.
|
||||
:param boolean check_followers: check in document followers
|
||||
"""
|
||||
partner_obj = self.pool['res.partner']
|
||||
partner_ids = []
|
||||
obj = None
|
||||
if id and (model or self._name != 'mail.thread') and check_followers:
|
||||
if model:
|
||||
obj = self.pool[model].browse(cr, uid, id, context=context)
|
||||
else:
|
||||
obj = self.browse(cr, uid, id, context=context)
|
||||
for contact in emails:
|
||||
partner_id = False
|
||||
email_address = tools.email_split(contact)
|
||||
if not email_address:
|
||||
partner_ids.append(partner_id)
|
||||
continue
|
||||
email_address = m.group(3)
|
||||
email_address = email_address[0]
|
||||
# first try: check in document's followers
|
||||
if obj:
|
||||
for follower in obj.message_follower_ids:
|
||||
if follower.email == email_address:
|
||||
partner_info['partner_id'] = follower.id
|
||||
# second try: check in partners
|
||||
if not partner_info.get('partner_id'):
|
||||
ids = partner_obj.search(cr, SUPERUSER_ID, [('email', 'ilike', email_address), ('user_ids', '!=', False)], limit=1, context=context)
|
||||
if not ids:
|
||||
ids = partner_obj.search(cr, SUPERUSER_ID, [('email', 'ilike', email_address)], limit=1, context=context)
|
||||
partner_id = follower.id
|
||||
# second try: check in partners that are also users
|
||||
if not partner_id:
|
||||
ids = partner_obj.search(cr, SUPERUSER_ID, [
|
||||
('email', 'ilike', email_address),
|
||||
('user_ids', '!=', False)
|
||||
], limit=1, context=context)
|
||||
if ids:
|
||||
partner_info['partner_id'] = ids[0]
|
||||
partner_id = ids[0]
|
||||
# third try: check in partners
|
||||
if not partner_id:
|
||||
ids = partner_obj.search(cr, SUPERUSER_ID, [
|
||||
('email', 'ilike', email_address)
|
||||
], limit=1, context=context)
|
||||
if ids:
|
||||
partner_id = ids[0]
|
||||
partner_ids.append(partner_id)
|
||||
return partner_ids
|
||||
|
||||
def message_partner_info_from_emails(self, cr, uid, id, emails, link_mail=False, context=None):
|
||||
""" Convert a list of emails into a list partner_ids and a list
|
||||
new_partner_ids. The return value is non conventional because
|
||||
it is meant to be used by the mail widget.
|
||||
|
||||
:return dict: partner_ids and new_partner_ids """
|
||||
mail_message_obj = self.pool.get('mail.message')
|
||||
partner_ids = self._find_partner_from_emails(cr, uid, id, emails, context=context)
|
||||
result = list()
|
||||
for idx in range(len(emails)):
|
||||
email_address = emails[idx]
|
||||
partner_id = partner_ids[idx]
|
||||
partner_info = {'full_name': email_address, 'partner_id': partner_id}
|
||||
result.append(partner_info)
|
||||
|
||||
# link mail with this from mail to the new partner id
|
||||
if link_mail and partner_info['partner_id']:
|
||||
message_ids = mail_message_obj.search(cr, SUPERUSER_ID, [
|
||||
'|',
|
||||
('email_from', '=', email),
|
||||
('email_from', 'ilike', '<%s>' % email),
|
||||
('email_from', '=', email_address),
|
||||
('email_from', 'ilike', '<%s>' % email_address),
|
||||
('author_id', '=', False)
|
||||
], context=context)
|
||||
if message_ids:
|
||||
|
@ -1156,18 +1278,7 @@ class mail_thread(osv.AbstractModel):
|
|||
del context['thread_model']
|
||||
return self.pool[model].message_post(cr, uid, thread_id, body=body, subject=subject, type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, content_subtype=content_subtype, **kwargs)
|
||||
|
||||
# 0: Parse email-from, try to find a better author_id based on document's followers for incoming emails
|
||||
email_from = kwargs.get('email_from')
|
||||
if email_from and thread_id and type == 'email' and kwargs.get('author_id'):
|
||||
email_list = tools.email_split(email_from)
|
||||
doc = self.browse(cr, uid, thread_id, context=context)
|
||||
if email_list and doc:
|
||||
author_ids = self.pool.get('res.partner').search(cr, uid, [
|
||||
('email', 'ilike', email_list[0]),
|
||||
('id', 'in', [f.id for f in doc.message_follower_ids])
|
||||
], limit=1, context=context)
|
||||
if author_ids:
|
||||
kwargs['author_id'] = author_ids[0]
|
||||
#0: Find the message's author, because we need it for private discussion
|
||||
author_id = kwargs.get('author_id')
|
||||
if author_id is None: # keep False values
|
||||
author_id = self.pool.get('mail.message')._get_default_author(cr, uid, context=context)
|
||||
|
@ -1278,21 +1389,6 @@ class mail_thread(osv.AbstractModel):
|
|||
self.message_subscribe(cr, uid, [thread_id], [message.author_id.id], context=context)
|
||||
return msg_id
|
||||
|
||||
#------------------------------------------------------
|
||||
# Compatibility methods: do not use
|
||||
# TDE TODO: remove me in 8.0
|
||||
#------------------------------------------------------
|
||||
|
||||
def message_create_partners_from_emails(self, cr, uid, emails, context=None):
|
||||
return {'partner_ids': [], 'new_partner_ids': []}
|
||||
|
||||
def message_post_user_api(self, cr, uid, thread_id, body='', parent_id=False,
|
||||
attachment_ids=None, content_subtype='plaintext',
|
||||
context=None, **kwargs):
|
||||
return self.message_post(cr, uid, thread_id, body=body, parent_id=parent_id,
|
||||
attachment_ids=attachment_ids, content_subtype=content_subtype,
|
||||
context=context, **kwargs)
|
||||
|
||||
#------------------------------------------------------
|
||||
# Followers API
|
||||
#------------------------------------------------------
|
||||
|
|
|
@ -23,6 +23,7 @@ from openerp.osv import fields, osv
|
|||
from openerp import SUPERUSER_ID
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class res_users(osv.Model):
|
||||
""" Update of res.users class
|
||||
- add a preference about sending emails about notifications
|
||||
|
@ -42,7 +43,6 @@ class res_users(osv.Model):
|
|||
}
|
||||
|
||||
_defaults = {
|
||||
'alias_domain': False, # always hide alias during creation
|
||||
'display_groups_suggestions': True,
|
||||
}
|
||||
|
||||
|
@ -63,25 +63,20 @@ class res_users(osv.Model):
|
|||
def _auto_init(self, cr, context=None):
|
||||
""" Installation hook: aliases, partner following themselves """
|
||||
# create aliases for all users and avoid constraint errors
|
||||
res = self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(res_users, self)._auto_init,
|
||||
self._columns['alias_id'], 'login', alias_force_key='id', context=context)
|
||||
return res
|
||||
return self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(res_users, self)._auto_init,
|
||||
self._name, self._columns['alias_id'], 'login', alias_force_key='id', context=context)
|
||||
|
||||
def create(self, cr, uid, data, context=None):
|
||||
# create default alias same as the login
|
||||
if not data.get('login', False):
|
||||
raise osv.except_osv(_('Invalid Action!'), _('You may not create a user. To create new users, you should use the "Settings > Users" menu.'))
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
mail_alias = self.pool.get('mail.alias')
|
||||
alias_id = mail_alias.create_unique_alias(cr, uid, {'alias_name': data['login']}, model_name=self._name, context=context)
|
||||
data['alias_id'] = alias_id
|
||||
data.pop('alias_name', None) # prevent errors during copy()
|
||||
|
||||
# create user
|
||||
user_id = super(res_users, self).create(cr, uid, data, context=context)
|
||||
create_context = dict(context, alias_model_name=self._name, alias_parent_model_name=self._name)
|
||||
user_id = super(res_users, self).create(cr, uid, data, context=create_context)
|
||||
user = self.browse(cr, uid, user_id, context=context)
|
||||
# alias
|
||||
mail_alias.write(cr, SUPERUSER_ID, [alias_id], {"alias_force_thread_id": user_id}, context)
|
||||
self.pool.get('mail.alias').write(cr, SUPERUSER_ID, [user.alias_id.id], {"alias_force_thread_id": user_id, "alias_parent_thread_id": user_id}, context)
|
||||
|
||||
# create a welcome message
|
||||
self._create_welcome_message(cr, uid, user, context=context)
|
||||
return user_id
|
||||
|
@ -95,12 +90,6 @@ class res_users(osv.Model):
|
|||
return self.pool.get('res.partner').message_post(cr, SUPERUSER_ID, [user.partner_id.id],
|
||||
body=body, context=context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
# User alias is sync'ed with login
|
||||
if vals.get('login'):
|
||||
vals['alias_name'] = vals['login']
|
||||
return super(res_users, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
# Cascade-delete mail aliases as well, as they should not exist without the user.
|
||||
alias_pool = self.pool.get('mail.alias')
|
||||
|
|
|
@ -22,21 +22,25 @@
|
|||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<field name="signature" position="before">
|
||||
<field name="notification_email_send"/>
|
||||
</field>
|
||||
<field name="signature" position="before">
|
||||
<field name="alias_domain" invisible="1"/>
|
||||
<field name="alias_id" readonly="1" required="0" attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
</field>
|
||||
<group string="Email preferences" position="after">
|
||||
<group name="misc" string="Miscellaneous"
|
||||
groups="base.group_no_one">
|
||||
<field name="display_groups_suggestions"/>
|
||||
</group>
|
||||
</group>
|
||||
</data>
|
||||
<data>
|
||||
<field name="signature" position="before">
|
||||
<field name="notification_email_send"/>
|
||||
</field>
|
||||
<field name="signature" position="before">
|
||||
<label for="alias_id" string="Messaging Alias" class="oe_read_only"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
<field name="alias_id" class="oe_read_only" required="0" nolabel="1"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
<label for="alias_name" string="Messaging Alias" class="oe_edit_only"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
<div class="oe_edit_only" attrs="{'invisible': [('alias_domain', '=', False)]}">
|
||||
<field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
|
||||
</div>
|
||||
<field name="alias_contact" string="Alias Accepts Emails From"
|
||||
attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
<field name="display_groups_suggestions" groups="base.group_no_one"/>
|
||||
</field>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -26,6 +26,16 @@
|
|||
border-radius: 0px;
|
||||
}
|
||||
|
||||
/* ---- GENERIC FOR MAIL-RELATED STUFF ---- */
|
||||
.openerp .oe_e.oe_e_alias {
|
||||
font-size: 30px;
|
||||
line-height: 15px;
|
||||
vertical-align: top;
|
||||
margin-right: 3px;
|
||||
color: white;
|
||||
text-shadow: 0px 0px 2px black;
|
||||
}
|
||||
|
||||
/* ------------ MAIL WIDGET --------------- */
|
||||
.openerp .oe_mail, .openerp .oe_mail *{
|
||||
-webkit-box-sizing: border-box;
|
||||
|
|
|
@ -632,10 +632,7 @@ openerp.mail = function (session) {
|
|||
// have unknown names -> call message_get_partner_info_from_emails to try to find partner_id
|
||||
var find_done = $.Deferred();
|
||||
if (names_to_find.length > 0) {
|
||||
var values = {
|
||||
'res_id': this.context.default_res_id,
|
||||
}
|
||||
find_done = self.parent_thread.ds_thread._model.call('message_get_partner_info_from_emails', [names_to_find], values);
|
||||
find_done = self.parent_thread.ds_thread._model.call('message_partner_info_from_emails', [this.context.default_res_id, names_to_find]);
|
||||
}
|
||||
else {
|
||||
find_done.resolve([]);
|
||||
|
@ -681,11 +678,7 @@ openerp.mail = function (session) {
|
|||
var new_names_to_find = _.difference(names_to_find, names_to_remove);
|
||||
find_done = $.Deferred();
|
||||
if (new_names_to_find.length > 0) {
|
||||
var values = {
|
||||
'link_mail': true,
|
||||
'res_id': self.context.default_res_id,
|
||||
}
|
||||
find_done = self.parent_thread.ds_thread._model.call('message_get_partner_info_from_emails', [new_names_to_find], values);
|
||||
find_done = self.parent_thread.ds_thread._model.call('message_partner_info_from_emails', [self.context.default_res_id, new_names_to_find, true]);
|
||||
}
|
||||
else {
|
||||
find_done.resolve([]);
|
||||
|
|
|
@ -71,9 +71,9 @@ class TestMailBase(common.TransactionCase):
|
|||
# Test users to use through the various tests
|
||||
self.res_users.write(cr, uid, uid, {'name': 'Administrator'})
|
||||
self.user_raoul_id = self.res_users.create(cr, uid,
|
||||
{'name': 'Raoul Grosbedon', 'signature': 'SignRaoul', 'email': 'raoul@raoul.fr', 'login': 'raoul', 'groups_id': [(6, 0, [self.group_employee_id])]})
|
||||
{'name': 'Raoul Grosbedon', 'signature': 'SignRaoul', 'email': 'raoul@raoul.fr', 'login': 'raoul', 'alias_name': 'raoul', 'groups_id': [(6, 0, [self.group_employee_id])]})
|
||||
self.user_bert_id = self.res_users.create(cr, uid,
|
||||
{'name': 'Bert Tartignole', 'signature': 'SignBert', 'email': 'bert@bert.fr', 'login': 'bert', 'groups_id': [(6, 0, [])]})
|
||||
{'name': 'Bert Tartignole', 'signature': 'SignBert', 'email': 'bert@bert.fr', 'login': 'bert', 'alias_name': 'bert', 'groups_id': [(6, 0, [])]})
|
||||
self.user_raoul = self.res_users.browse(cr, uid, self.user_raoul_id)
|
||||
self.user_bert = self.res_users.browse(cr, uid, self.user_bert_id)
|
||||
self.user_admin = self.res_users.browse(cr, uid, uid)
|
||||
|
@ -83,7 +83,7 @@ class TestMailBase(common.TransactionCase):
|
|||
|
||||
# Test 'pigs' group to use through the various tests
|
||||
self.group_pigs_id = self.mail_group.create(cr, uid,
|
||||
{'name': 'Pigs', 'description': 'Fans of Pigs, unite !'},
|
||||
{'name': 'Pigs', 'description': 'Fans of Pigs, unite !', 'alias_name': 'group+pigs'},
|
||||
{'mail_create_nolog': True})
|
||||
self.group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
||||
|
||||
|
|
|
@ -32,17 +32,17 @@ class test_mail(TestMailBase):
|
|||
""" Test basic mail.alias setup works, before trying to use them for routing """
|
||||
cr, uid = self.cr, self.uid
|
||||
self.user_valentin_id = self.res_users.create(cr, uid,
|
||||
{'name': 'Valentin Cognito', 'email': 'valentin.cognito@gmail.com', 'login': 'valentin.cognito'})
|
||||
{'name': 'Valentin Cognito', 'email': 'valentin.cognito@gmail.com', 'login': 'valentin.cognito', 'alias_name': 'valentin.cognito'})
|
||||
self.user_valentin = self.res_users.browse(cr, uid, self.user_valentin_id)
|
||||
self.assertEquals(self.user_valentin.alias_name, self.user_valentin.login, "Login should be used as alias")
|
||||
|
||||
self.user_pagan_id = self.res_users.create(cr, uid,
|
||||
{'name': 'Pagan Le Marchant', 'email': 'plmarchant@gmail.com', 'login': 'plmarchant@gmail.com'})
|
||||
{'name': 'Pagan Le Marchant', 'email': 'plmarchant@gmail.com', 'login': 'plmarchant@gmail.com', 'alias_name': 'plmarchant@gmail.com'})
|
||||
self.user_pagan = self.res_users.browse(cr, uid, self.user_pagan_id)
|
||||
self.assertEquals(self.user_pagan.alias_name, 'plmarchant', "If login is an email, the alias should keep only the local part")
|
||||
|
||||
self.user_barty_id = self.res_users.create(cr, uid,
|
||||
{'name': 'Bartholomew Ironside', 'email': 'barty@gmail.com', 'login': 'b4r+_#_R3wl$$'})
|
||||
{'name': 'Bartholomew Ironside', 'email': 'barty@gmail.com', 'login': 'b4r+_#_R3wl$$', 'alias_name': 'b4r+_#_R3wl$$'})
|
||||
self.user_barty = self.res_users.browse(cr, uid, self.user_barty_id)
|
||||
self.assertEquals(self.user_barty.alias_name, 'b4r+_-_r3wl-', 'Disallowed chars should be replaced by hyphens')
|
||||
|
||||
|
|
|
@ -99,20 +99,20 @@ class TestMailgateway(TestMailBase):
|
|||
# --------------------------------------------------
|
||||
|
||||
# Do: find partner with email -> first partner should be found
|
||||
partner_info = self.mail_thread.message_find_partner_from_emails(cr, uid, None, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
|
||||
partner_info = self.mail_thread.message_partner_info_from_emails(cr, uid, None, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
|
||||
self.assertEqual(partner_info['full_name'], 'Maybe Raoul <test@test.fr>',
|
||||
'mail_thread: message_find_partner_from_emails did not handle email')
|
||||
'mail_thread: message_partner_info_from_emails did not handle email')
|
||||
self.assertEqual(partner_info['partner_id'], p_a_id,
|
||||
'mail_thread: message_find_partner_from_emails wrong partner found')
|
||||
'mail_thread: message_partner_info_from_emails wrong partner found')
|
||||
|
||||
# Data: add some data about partners
|
||||
# 2 - User BRaoul
|
||||
p_b_id = self.res_partner.create(cr, uid, {'name': 'BRaoul', 'email': 'test@test.fr', 'user_ids': [(4, user_raoul.id)]})
|
||||
|
||||
# Do: find partner with email -> first user should be found
|
||||
partner_info = self.mail_thread.message_find_partner_from_emails(cr, uid, None, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
|
||||
partner_info = self.mail_thread.message_partner_info_from_emails(cr, uid, None, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
|
||||
self.assertEqual(partner_info['partner_id'], p_b_id,
|
||||
'mail_thread: message_find_partner_from_emails wrong partner found')
|
||||
'mail_thread: message_partner_info_from_emails wrong partner found')
|
||||
|
||||
# --------------------------------------------------
|
||||
# CASE1: with object
|
||||
|
@ -120,9 +120,9 @@ class TestMailgateway(TestMailBase):
|
|||
|
||||
# Do: find partner in group where there is a follower with the email -> should be taken
|
||||
self.mail_group.message_subscribe(cr, uid, [group_pigs.id], [p_b_id])
|
||||
partner_info = self.mail_group.message_find_partner_from_emails(cr, uid, group_pigs.id, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
|
||||
partner_info = self.mail_group.message_partner_info_from_emails(cr, uid, group_pigs.id, ['Maybe Raoul <test@test.fr>'], link_mail=False)[0]
|
||||
self.assertEqual(partner_info['partner_id'], p_b_id,
|
||||
'mail_thread: message_find_partner_from_emails wrong partner found')
|
||||
'mail_thread: message_partner_info_from_emails wrong partner found')
|
||||
|
||||
def test_05_mail_message_mail_mail(self):
|
||||
""" Tests designed for testing email values based on mail.message, aliases, ... """
|
||||
|
@ -189,6 +189,7 @@ class TestMailgateway(TestMailBase):
|
|||
|
||||
# Data: set catchall domain
|
||||
self.registry('ir.config_parameter').set_param(cr, uid, 'mail.catchall.domain', alias_domain)
|
||||
self.registry('ir.config_parameter').unlink(cr, uid, self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.alias')]))
|
||||
|
||||
# Update message
|
||||
self.mail_message.write(cr, user_raoul_id, [msg_id], {'email_from': False, 'reply_to': False})
|
||||
|
@ -220,87 +221,6 @@ class TestMailgateway(TestMailBase):
|
|||
self.assertEqual(mail.reply_to, msg.email_from,
|
||||
'mail_mail: incorrect reply_to: should be message email_from')
|
||||
|
||||
def test_05_mail_message_mail_mail(self):
|
||||
""" Tests designed for testing email values based on mail.message, aliases, ... """
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Data: clean catchall domain
|
||||
param_ids = self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.domain')])
|
||||
self.registry('ir.config_parameter').unlink(cr, uid, param_ids)
|
||||
|
||||
# Do: create a mail_message with a reply_to, without message-id
|
||||
msg_id = self.mail_message.create(cr, uid, {'subject': 'Subject', 'body': 'Body', 'reply_to': 'custom@example.com'})
|
||||
msg = self.mail_message.browse(cr, uid, msg_id)
|
||||
# Test: message content
|
||||
self.assertIn('reply_to', msg.message_id,
|
||||
'mail_message: message_id should be specific to a mail_message with a given reply_to')
|
||||
self.assertEqual('custom@example.com', msg.reply_to,
|
||||
'mail_message: incorrect reply_to')
|
||||
# Do: create a mail_mail with the previous mail_message and specified reply_to
|
||||
mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'reply_to': 'other@example.com', 'state': 'cancel'})
|
||||
mail = self.mail_mail.browse(cr, uid, mail_id)
|
||||
# Test: mail_mail content
|
||||
self.assertEqual(mail.reply_to, 'other@example.com',
|
||||
'mail_mail: reply_to should be equal to the one coming from creation values')
|
||||
# Do: create a mail_mail with the previous mail_message
|
||||
self.mail_message.write(cr, uid, [msg_id], {'reply_to': 'custom@example.com'})
|
||||
msg.refresh()
|
||||
mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
|
||||
mail = self.mail_mail.browse(cr, uid, mail_id)
|
||||
# Test: mail_mail content
|
||||
self.assertEqual(mail.reply_to, msg.reply_to,
|
||||
'mail_mail: reply_to should be equal to the one coming from the mail_message')
|
||||
|
||||
# Do: create a mail_message without a reply_to
|
||||
msg_id = self.mail_message.create(cr, uid, {'subject': 'Subject', 'body': 'Body', 'model': 'mail.group', 'res_id': self.group_pigs_id, 'email_from': False})
|
||||
msg = self.mail_message.browse(cr, uid, msg_id)
|
||||
# Test: message content
|
||||
self.assertIn('mail.group', msg.message_id,
|
||||
'mail_message: message_id should contain model')
|
||||
self.assertIn('%s' % self.group_pigs_id, msg.message_id,
|
||||
'mail_message: message_id should contain res_id')
|
||||
self.assertFalse(msg.reply_to,
|
||||
'mail_message: should not generate a reply_to address when not specified')
|
||||
# Do: create a mail_mail based on the previous mail_message
|
||||
mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
|
||||
mail = self.mail_mail.browse(cr, uid, mail_id)
|
||||
# Test: mail_mail content
|
||||
self.assertFalse(mail.reply_to,
|
||||
'mail_mail: reply_to should not have been guessed')
|
||||
# Update message
|
||||
self.mail_message.write(cr, uid, [msg_id], {'email_from': 'someone@example.com'})
|
||||
msg.refresh()
|
||||
# Do: create a mail_mail based on the previous mail_message
|
||||
mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
|
||||
mail = self.mail_mail.browse(cr, uid, mail_id)
|
||||
# Test: mail_mail content
|
||||
self.assertEqual(email_split(mail.reply_to), email_split(msg.email_from),
|
||||
'mail_mail: reply_to should be equal to mail_message.email_from when having no document or default alias')
|
||||
|
||||
# Data: set catchall domain
|
||||
self.registry('ir.config_parameter').set_param(cr, uid, 'mail.catchall.domain', 'schlouby.fr')
|
||||
self.registry('ir.config_parameter').unlink(cr, uid, self.registry('ir.config_parameter').search(cr, uid, [('key', '=', 'mail.catchall.alias')]))
|
||||
|
||||
# Update message
|
||||
self.mail_message.write(cr, uid, [msg_id], {'email_from': False, 'reply_to': False})
|
||||
msg.refresh()
|
||||
# Do: create a mail_mail based on the previous mail_message
|
||||
mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
|
||||
mail = self.mail_mail.browse(cr, uid, mail_id)
|
||||
# Test: mail_mail content
|
||||
self.assertEqual(mail.reply_to, '"Followers of Pigs" <group+pigs@schlouby.fr>',
|
||||
'mail_mail: reply_to should equal the mail.group alias')
|
||||
|
||||
# Update message
|
||||
self.mail_message.write(cr, uid, [msg_id], {'res_id': False, 'email_from': 'someone@schlouby.fr', 'reply_to': False})
|
||||
msg.refresh()
|
||||
# Do: create a mail_mail based on the previous mail_message
|
||||
mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
|
||||
mail = self.mail_mail.browse(cr, uid, mail_id)
|
||||
# Test: mail_mail content
|
||||
self.assertEqual(mail.reply_to, msg.email_from,
|
||||
'mail_mail: reply_to should equal the mail_message email_from')
|
||||
|
||||
# Data: set catchall alias
|
||||
self.registry('ir.config_parameter').set_param(self.cr, self.uid, 'mail.catchall.alias', 'gateway')
|
||||
|
||||
|
@ -310,7 +230,7 @@ class TestMailgateway(TestMailBase):
|
|||
# Do: create a mail_mail based on the previous mail_message
|
||||
mail_id = self.mail_mail.create(cr, uid, {'mail_message_id': msg_id, 'state': 'cancel'})
|
||||
mail = self.mail_mail.browse(cr, uid, mail_id)
|
||||
# Test: mail_mail content
|
||||
# Test: mail_mail Content-Type
|
||||
self.assertEqual(mail.reply_to, 'gateway@schlouby.fr',
|
||||
'mail_mail: reply_to should equal the catchall email alias')
|
||||
|
||||
|
@ -351,7 +271,10 @@ class TestMailgateway(TestMailBase):
|
|||
alias_id = self.mail_alias.create(cr, uid, {
|
||||
'alias_name': 'groups',
|
||||
'alias_user_id': False,
|
||||
'alias_model_id': self.mail_group_model_id})
|
||||
'alias_model_id': self.mail_group_model_id,
|
||||
'alias_parent_model_id': self.mail_group_model_id,
|
||||
'alias_parent_thread_id': self.group_pigs_id,
|
||||
'alias_contact': 'everyone'})
|
||||
|
||||
# --------------------------------------------------
|
||||
# Test1: new record creation
|
||||
|
@ -392,12 +315,42 @@ class TestMailgateway(TestMailBase):
|
|||
# Data: unlink group
|
||||
frog_group.unlink()
|
||||
|
||||
# Do: incoming email from a known partner on an alias with known recipients, alias is owned by user that can create a group
|
||||
self.mail_alias.write(cr, uid, [alias_id], {'alias_user_id': self.user_raoul_id})
|
||||
p1id = self.res_partner.create(cr, uid, {'name': 'Sylvie Lelitre', 'email': 'test.sylvie.lelitre@agrolait.com'})
|
||||
p2id = self.res_partner.create(cr, uid, {'name': 'Other Poilvache', 'email': 'other@gmail.com'})
|
||||
# Do: incoming email from an unknown partner on a Partners only alias -> bounce
|
||||
self._init_mock_build_email()
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
|
||||
self.mail_alias.write(cr, uid, [alias_id], {'alias_contact': 'partners'})
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other2@gmail.com')
|
||||
# Test: no group created
|
||||
self.assertTrue(len(frog_groups) == 0)
|
||||
# Test: email bounced
|
||||
sent_emails = self._build_email_kwargs_list
|
||||
self.assertEqual(len(sent_emails), 1,
|
||||
'message_process: incoming email on Partners alias should send a bounce email')
|
||||
self.assertIn('Frogs', sent_emails[0].get('subject'),
|
||||
'message_process: bounce email on Partners alias should contain the original subject')
|
||||
self.assertIn('test.sylvie.lelitre@agrolait.com', sent_emails[0].get('email_to'),
|
||||
'message_process: bounce email on Partners alias should have original email sender as recipient')
|
||||
|
||||
# Do: incoming email from an unknown partner on a Followers only alias -> bounce
|
||||
self._init_mock_build_email()
|
||||
self.mail_alias.write(cr, uid, [alias_id], {'alias_contact': 'followers'})
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other3@gmail.com')
|
||||
# Test: no group created
|
||||
self.assertTrue(len(frog_groups) == 0)
|
||||
# Test: email bounced
|
||||
sent_emails = self._build_email_kwargs_list
|
||||
self.assertEqual(len(sent_emails), 1,
|
||||
'message_process: incoming email on Followers alias should send a bounce email')
|
||||
self.assertIn('Frogs', sent_emails[0].get('subject'),
|
||||
'message_process: bounce email on Followers alias should contain the original subject')
|
||||
self.assertIn('test.sylvie.lelitre@agrolait.com', sent_emails[0].get('email_to'),
|
||||
'message_process: bounce email on Followers alias should have original email sender as recipient')
|
||||
|
||||
# Do: incoming email from a known partner on a Partners alias -> ok (+ test on alias.user_id)
|
||||
self.mail_alias.write(cr, uid, [alias_id], {'alias_user_id': self.user_raoul_id, 'alias_contact': 'partners'})
|
||||
p1id = self.res_partner.create(cr, uid, {'name': 'Sylvie Lelitre', 'email': 'test.sylvie.lelitre@agrolait.com'})
|
||||
p2id = self.res_partner.create(cr, uid, {'name': 'Other Poilvache', 'email': 'other4@gmail.com'})
|
||||
self._init_mock_build_email()
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other4@gmail.com')
|
||||
sent_emails = self._build_email_kwargs_list
|
||||
# Test: one group created by Raoul
|
||||
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
|
||||
|
@ -409,24 +362,37 @@ class TestMailgateway(TestMailBase):
|
|||
self.assertEqual(len(frog_group.message_ids), 1,
|
||||
'message_process: newly created group should have the incoming email in message_ids')
|
||||
msg = frog_group.message_ids[0]
|
||||
# Test: message: unknown email address -> message has email_from, not author_id
|
||||
# Test: message: author found
|
||||
self.assertEqual(p1id, msg.author_id.id,
|
||||
'message_process: message on created group should have Sylvie as author_id')
|
||||
self.assertIn('Sylvie Lelitre <test.sylvie.lelitre@agrolait.com>', msg.email_from,
|
||||
'message_process: message on created group should have have an email_from')
|
||||
# Test: author (not recipient and not raoul (as alias owner)) added as follower
|
||||
# Test: author (not recipient and not Raoul (as alias owner)) added as follower
|
||||
frog_follower_ids = set([p.id for p in frog_group.message_follower_ids])
|
||||
self.assertEqual(frog_follower_ids, set([p1id]),
|
||||
'message_process: newly created group should have 1 follower (author, not creator, not recipients)')
|
||||
# Test: sent emails: no-one, no bounce effet
|
||||
sent_emails = self._build_email_kwargs_list
|
||||
self.assertEqual(len(sent_emails), 0,
|
||||
'message_process: should not bounce incoming emails')
|
||||
# Data: unlink group
|
||||
frog_group.unlink()
|
||||
|
||||
# Do: incoming email from a known partner that is also an user that can create a mail.group
|
||||
self.res_users.create(cr, uid, {'partner_id': p1id, 'login': 'sylvie', 'groups_id': [(6, 0, [self.group_employee_id])]})
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other@gmail.com')
|
||||
# Do: incoming email from a not follower Partner on a Followers only alias -> bounce
|
||||
self._init_mock_build_email()
|
||||
self.mail_alias.write(cr, uid, [alias_id], {'alias_user_id': False, 'alias_contact': 'followers'})
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other5@gmail.com')
|
||||
# Test: no group created
|
||||
self.assertTrue(len(frog_groups) == 0)
|
||||
# Test: email bounced
|
||||
sent_emails = self._build_email_kwargs_list
|
||||
self.assertEqual(len(sent_emails), 1,
|
||||
'message_process: incoming email on Partners alias should send a bounce email')
|
||||
|
||||
# Do: incoming email from a parent document follower on a Followers only alias -> ok
|
||||
self._init_mock_build_email()
|
||||
self.mail_group.message_subscribe(cr, uid, [self.group_pigs_id], [p1id])
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, to='groups@example.com, other6@gmail.com')
|
||||
# Test: one group created by Raoul (or Sylvie maybe, if we implement it)
|
||||
self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created')
|
||||
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
|
||||
|
@ -438,15 +404,63 @@ class TestMailgateway(TestMailBase):
|
|||
self.assertEqual(frog_follower_ids, set([p1id]),
|
||||
'message_process: newly created group should have 1 follower (author, not creator, not recipients)')
|
||||
# Test: sent emails: no-one, no bounce effet
|
||||
sent_emails = self._build_email_kwargs_list
|
||||
self.assertEqual(len(sent_emails), 0,
|
||||
'message_process: should not bounce incoming emails')
|
||||
|
||||
# --------------------------------------------------
|
||||
# Test2: discussion update
|
||||
# Test2: update-like alias
|
||||
# --------------------------------------------------
|
||||
|
||||
# Do: Pigs alias is restricted, should bounce
|
||||
self._init_mock_build_email()
|
||||
self.mail_group.write(cr, uid, [frog_group.id], {'alias_name': 'frogs', 'alias_contact': 'followers', 'alias_force_thread_id': frog_group.id})
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com',
|
||||
msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>',
|
||||
to='frogs@example.com>', subject='Re: news')
|
||||
# Test: no group 'Re: news' created, still only 1 Frogs group
|
||||
self.assertEqual(len(frog_groups), 0,
|
||||
'message_process: reply on Frogs should not have created a new group with new subject')
|
||||
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
|
||||
self.assertEqual(len(frog_groups), 1,
|
||||
'message_process: reply on Frogs should not have created a duplicate group with old subject')
|
||||
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
|
||||
# Test: email bounced
|
||||
sent_emails = self._build_email_kwargs_list
|
||||
self.assertEqual(len(sent_emails), 1,
|
||||
'message_process: incoming email on Followers alias should send a bounce email')
|
||||
self.assertIn('Re: news', sent_emails[0].get('subject'),
|
||||
'message_process: bounce email on Followers alias should contain the original subject')
|
||||
|
||||
# Do: Pigs alias is restricted, should accept Followers
|
||||
self._init_mock_build_email()
|
||||
self.mail_group.message_subscribe(cr, uid, [frog_group.id], [p2id])
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com',
|
||||
msg_id='<1198923581.41972151344608186799.JavaMail.diff1@agrolait.com>',
|
||||
to='frogs@example.com>', subject='Re: cats')
|
||||
# Test: no group 'Re: news' created, still only 1 Frogs group
|
||||
self.assertEqual(len(frog_groups), 0,
|
||||
'message_process: reply on Frogs should not have created a new group with new subject')
|
||||
frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'Frogs')])
|
||||
self.assertEqual(len(frog_groups), 1,
|
||||
'message_process: reply on Frogs should not have created a duplicate group with old subject')
|
||||
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
|
||||
# Test: one new message
|
||||
self.assertEqual(len(frog_group.message_ids), 2, 'message_process: group should contain 2 messages after reply')
|
||||
# Test: sent emails: 1 (Sylvie copy of the incoming email, but no bounce)
|
||||
sent_emails = self._build_email_kwargs_list
|
||||
self.assertEqual(len(sent_emails), 1,
|
||||
'message_process: one email should have been generated')
|
||||
self.assertIn('test.sylvie.lelitre@agrolait.com', sent_emails[0].get('email_to')[0],
|
||||
'message_process: email should be sent to Sylvie')
|
||||
self.mail_group.message_unsubscribe(cr, uid, [frog_group.id], [p2id])
|
||||
|
||||
# --------------------------------------------------
|
||||
# Test3: discussion and replies
|
||||
# --------------------------------------------------
|
||||
|
||||
# Do: even with a wrong destination, a reply should end up in the correct thread
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other@gmail.com',
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com',
|
||||
msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>',
|
||||
to='erroneous@example.com>', subject='Re: news',
|
||||
extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
|
||||
|
@ -458,14 +472,14 @@ class TestMailgateway(TestMailBase):
|
|||
'message_process: reply on Frogs should not have created a duplicate group with old subject')
|
||||
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
|
||||
# Test: one new message
|
||||
self.assertEqual(len(frog_group.message_ids), 2, 'message_process: group should contain 2 messages after reply')
|
||||
self.assertEqual(len(frog_group.message_ids), 3, 'message_process: group should contain 2 messages after reply')
|
||||
# Test: author (and not recipient) added as follower
|
||||
frog_follower_ids = set([p.id for p in frog_group.message_follower_ids])
|
||||
self.assertEqual(frog_follower_ids, set([p1id, p2id]),
|
||||
'message_process: after reply, group should have 2 followers')
|
||||
|
||||
# Do: due to some issue, same email goes back into the mailgateway
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other@gmail.com',
|
||||
frog_groups = format_and_process(MAIL_TEMPLATE, email_from='other4@gmail.com',
|
||||
msg_id='<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>',
|
||||
subject='Re: news', extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
|
||||
# Test: no group 'Re: news' created, still only 1 Frogs group
|
||||
|
@ -476,20 +490,18 @@ class TestMailgateway(TestMailBase):
|
|||
'message_process: reply on Frogs should not have created a duplicate group with old subject')
|
||||
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
|
||||
# Test: no new message
|
||||
self.assertEqual(len(frog_group.message_ids), 2, 'message_process: message with already existing message_id should not have been duplicated')
|
||||
self.assertEqual(len(frog_group.message_ids), 3, 'message_process: message with already existing message_id should not have been duplicated')
|
||||
# Test: message_id is still unique
|
||||
msg_ids = self.mail_message.search(cr, uid, [('message_id', 'ilike', '<1198923581.41972151344608186760.JavaMail.diff1@agrolait.com>')])
|
||||
self.assertEqual(len(msg_ids), 1,
|
||||
'message_process: message with already existing message_id should not have been duplicated')
|
||||
|
||||
# --------------------------------------------------
|
||||
# Test3: email_from and partner finding
|
||||
# Test4: email_from and partner finding
|
||||
# --------------------------------------------------
|
||||
|
||||
# Data: extra partner with Raoul's email -> test the 'better author finding'
|
||||
extra_partner_id = self.res_partner.create(cr, uid, {'name': 'A-Raoul', 'email': 'test_raoul@email.com'})
|
||||
# extra_user_id = self.res_users.create(cr, uid, {'name': 'B-Raoul', 'email': self.user_raoul.email})
|
||||
# extra_user_pid = self.res_users.browse(cr, uid, extra_user_id).partner_id.id
|
||||
|
||||
# Do: post a new message, with a known partner -> duplicate emails -> partner
|
||||
format_and_process(MAIL_TEMPLATE, email_from='Lombrik Lubrik <test_raoul@email.com>',
|
||||
|
@ -534,7 +546,7 @@ class TestMailgateway(TestMailBase):
|
|||
self.res_users.write(cr, uid, self.user_raoul_id, {'email': raoul_email})
|
||||
|
||||
# --------------------------------------------------
|
||||
# Test4: misc gateway features
|
||||
# Test5: misc gateway features
|
||||
# --------------------------------------------------
|
||||
|
||||
# Do: incoming email with model that does not accepts incoming emails must raise
|
||||
|
@ -568,7 +580,7 @@ class TestMailgateway(TestMailBase):
|
|||
frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
|
||||
msg = frog_group.message_ids[0]
|
||||
# Test: plain text content should be wrapped and stored as html
|
||||
self.assertEqual(msg.body, '<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>',
|
||||
self.assertIn('<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>', msg.body,
|
||||
'message_process: plaintext incoming email incorrectly parsed')
|
||||
|
||||
@mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm')
|
||||
|
|
|
@ -0,0 +1,512 @@
|
|||
# Thai translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-06-20 13:55+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Thai <th@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-21 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "Mako"
|
||||
msgstr "Mako"
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/wizard/share_wizard.py:50
|
||||
#, python-format
|
||||
msgid "Please select at least one user to share with"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.wizard:0
|
||||
msgid ""
|
||||
"Select which contacts should belong to the portal in the list below.\n"
|
||||
" The email address of each selected contact must be "
|
||||
"valid and unique.\n"
|
||||
" If necessary, you can fix any contact's email "
|
||||
"address directly in the list."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:mail.group,name:portal.company_jobs
|
||||
msgid "Company Jobs"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "amount: the total amount to pay, as a float"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.wizard.user:0
|
||||
msgid "Contacts"
|
||||
msgstr "ที่อยู่ติดต่อ"
|
||||
|
||||
#. module: portal
|
||||
#: view:share.wizard:0
|
||||
#: field:share.wizard,group_ids:0
|
||||
msgid "Existing groups"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:res.groups:0
|
||||
msgid "Portal Groups"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.wizard,welcome_message:0
|
||||
msgid "Invitation Message"
|
||||
msgstr "ข้อความเชื้อเชิญ"
|
||||
|
||||
#. module: portal
|
||||
#: view:res.groups:0
|
||||
msgid "Non-Portal Groups"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/wizard/share_wizard.py:54
|
||||
#, python-format
|
||||
msgid "Please select at least one group to share with"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:share.wizard:0
|
||||
msgid "Details"
|
||||
msgstr "รายละเอียด"
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.ui.menu,name:portal.portal_orders
|
||||
msgid "Quotations and Sales Orders"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "reference: the reference number of the document to pay"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: help:portal.payment.acquirer,visible:0
|
||||
msgid ""
|
||||
"Make this payment acquirer available in portal forms (Customer invoices, "
|
||||
"etc.)"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.model,name:portal.model_share_wizard
|
||||
msgid "Share Wizard"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.wizard.user,email:0
|
||||
msgid "Email"
|
||||
msgstr "อีเมล์"
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.actions.client,help:portal.action_news
|
||||
msgid ""
|
||||
"<p>\n"
|
||||
" Youd don't have unread company's news.\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/wizard/portal_wizard.py:194
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You must have an email address in your User Preferences to send emails."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.actions.client,name:portal.action_jobs
|
||||
#: model:ir.ui.menu,name:portal.portal_jobs
|
||||
msgid "Jobs"
|
||||
msgstr "งาน"
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.wizard,user_ids:0
|
||||
msgid "Users"
|
||||
msgstr "ผู้ใช้งาน"
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/acquirer.py:82
|
||||
#, python-format
|
||||
msgid "Pay safely online"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/acquirer.py:77
|
||||
#, python-format
|
||||
msgid "No online payment acquirers configured"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid ""
|
||||
"kind: the kind of document on which the payment form is rendered (translated "
|
||||
"to user language, e.g. \"Invoice\")"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: help:portal.wizard,portal_id:0
|
||||
msgid "The portal that users can be added in or removed from."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/wizard/share_wizard.py:38
|
||||
#, python-format
|
||||
msgid "Users you already shared with"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.actions.client,help:portal.action_jobs
|
||||
msgid ""
|
||||
"<p>\n"
|
||||
" Youd don't have unread job offers.\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid ""
|
||||
", so it may use Mako expressions.\n"
|
||||
" The Mako evaluation context provides:"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.ui.menu,name:portal.portal_menu
|
||||
#: field:portal.wizard,portal_id:0
|
||||
#: field:res.groups,is_portal:0
|
||||
#: model:res.groups,name:portal.group_portal
|
||||
msgid "Portal"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/wizard/portal_wizard.py:34
|
||||
#, python-format
|
||||
msgid "Your OpenERP account at %(company)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:res.groups,name:portal.group_anonymous
|
||||
msgid "Anonymous"
|
||||
msgstr "ผู้ใช้นิรนาม"
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.wizard.user,in_portal:0
|
||||
msgid "In Portal"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.actions.client,name:portal.action_news
|
||||
#: model:ir.ui.menu,name:portal.portal_company_news
|
||||
msgid "News"
|
||||
msgstr "ข่าว"
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.ui.menu,name:portal.portal_after_sales
|
||||
msgid "After Sale Services"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:res.groups,comment:portal.group_portal
|
||||
msgid ""
|
||||
"Portal members have specific access rights (such as record rules and "
|
||||
"restricted menus).\n"
|
||||
" They usually do not belong to the usual OpenERP groups."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.actions.act_window,name:portal.action_acquirer_list
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "Payment Acquirers"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.ui.menu,name:portal.portal_projects
|
||||
msgid "Projects"
|
||||
msgstr "โครงการ"
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.actions.client,name:portal.action_mail_inbox_feeds_portal
|
||||
#: model:ir.ui.menu,name:portal.portal_inbox
|
||||
msgid "Inbox"
|
||||
msgstr "กล่องขาเข้า"
|
||||
|
||||
#. module: portal
|
||||
#: view:share.wizard:0
|
||||
#: field:share.wizard,user_ids:0
|
||||
msgid "Existing users"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.wizard.user,wizard_id:0
|
||||
msgid "Wizard"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.payment.acquirer,name:0
|
||||
msgid "Name"
|
||||
msgstr "ชื่อ"
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.model,name:portal.model_res_groups
|
||||
msgid "Access Groups"
|
||||
msgstr "กลุ่มการเข้าถึง"
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "uid: the current user id"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid ""
|
||||
"quote(): a method to quote special string character to make them suitable "
|
||||
"for inclusion in a URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: help:res.groups,is_portal:0
|
||||
msgid "If checked, this group is usable as a portal."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.payment.acquirer,form_template:0
|
||||
msgid "Payment form template (HTML)"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.wizard.user,partner_id:0
|
||||
msgid "Contact"
|
||||
msgstr "ที่อยู่ติดต่อ"
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.model,name:portal.model_mail_mail
|
||||
msgid "Outgoing Mails"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/wizard/portal_wizard.py:193
|
||||
#, python-format
|
||||
msgid "Email required"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.ui.menu,name:portal.portal_messages
|
||||
msgid "Messaging"
|
||||
msgstr "Messaging"
|
||||
|
||||
#. module: portal
|
||||
#: model:res.groups,comment:portal.group_anonymous
|
||||
msgid ""
|
||||
"Anonymous users have specific access rights (such as record rules and "
|
||||
"restricted menus).\n"
|
||||
" They usually do not belong to the usual OpenERP groups."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.model,name:portal.model_portal_payment_acquirer
|
||||
msgid "Online Payment Acquirer"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:mail.group,name:portal.company_news_feed
|
||||
msgid "Company News"
|
||||
msgstr "ข่าวสารบริษัท"
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/acquirer.py:76
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You can finish the configuration in the <a href=\"%s\">Bank&Cash settings</a>"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "cr: the current database cursor"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.actions.client,help:portal.action_mail_inbox_feeds_portal
|
||||
msgid ""
|
||||
"<p>\n"
|
||||
" <b>Good Job!</b> Your inbox is empty.\n"
|
||||
" </p><p>\n"
|
||||
" Your inbox contains private messages or emails sent to "
|
||||
"you\n"
|
||||
" as well as information related to documents or people "
|
||||
"you\n"
|
||||
" follow.\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"<p>\n"
|
||||
" <b>เยี่ยมยอด!</b> คุณอ่านข้อความหมดแล้ว\n"
|
||||
" </p><p>\n"
|
||||
" <b>ขอความร่วมมือ</b> ภาษาไทยสำหรับ OpenERP นั้น "
|
||||
"ยังไม่สมบรูณ์และถูกต้อง \n"
|
||||
" <p> เลือกหมวด Translations เพื่อแนะนำการแปลได้ที่ </p>\n"
|
||||
"\n"
|
||||
" https://launchpad.net/openobject-addons : business "
|
||||
"application modules\n"
|
||||
" https://launchpad.net/openobject-server : the "
|
||||
"framework\n"
|
||||
" https://launchpad.net/openerp-web : web "
|
||||
"modules and frontend\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid ""
|
||||
"object: the document on which the payment form is rendered (usually an "
|
||||
"invoice or sales order record)"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: help:portal.wizard,welcome_message:0
|
||||
msgid "This text is included in the email sent to new users of the portal."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.ui.menu,name:portal.portal_company
|
||||
msgid "About Us"
|
||||
msgstr "เกี่ยวกับตัวเอง"
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid ""
|
||||
"currency: the currency record in which the document is issued (e.g. "
|
||||
"currency.name could be EUR)"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "Payment Acquirer"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/wizard/portal_wizard.py:35
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Dear %(name)s,\n"
|
||||
"\n"
|
||||
"You have been given access to %(portal)s.\n"
|
||||
"\n"
|
||||
"Your login account data is:\n"
|
||||
"Database: %(db)s\n"
|
||||
"Username: %(login)s\n"
|
||||
"\n"
|
||||
"In order to complete the signin process, click on the following url:\n"
|
||||
"%(url)s\n"
|
||||
"\n"
|
||||
"%(welcome_message)s\n"
|
||||
"\n"
|
||||
"--\n"
|
||||
"OpenERP - Open Source Business Applications\n"
|
||||
"http://www.openerp.com\n"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.wizard:0
|
||||
msgid "or"
|
||||
msgstr "หรือ"
|
||||
|
||||
#. module: portal
|
||||
#: model:portal.payment.acquirer,form_template:portal.paypal_acquirer
|
||||
msgid ""
|
||||
"\n"
|
||||
"% if object.company_id.paypal_account:\n"
|
||||
"<form action=\"https://www.paypal.com/cgi-bin/webscr\" method=\"post\" "
|
||||
"target=\"_blank\">\n"
|
||||
" <input type=\"hidden\" name=\"cmd\" value=\"_xclick\"/>\n"
|
||||
" <input type=\"hidden\" name=\"business\" "
|
||||
"value=\"${object.company_id.paypal_account}\"/>\n"
|
||||
" <input type=\"hidden\" name=\"item_name\" "
|
||||
"value=\"${object.company_id.name} ${kind.title()} ${reference}\"/>\n"
|
||||
" <input type=\"hidden\" name=\"amount\" value=\"${amount}\"/>\n"
|
||||
" <input type=\"hidden\" name=\"currency_code\" "
|
||||
"value=\"${currency.name}\"/>\n"
|
||||
" <input type=\"image\" name=\"submit\" "
|
||||
"src=\"https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif\"/>\n"
|
||||
"</form>\n"
|
||||
"% endif\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.model,name:portal.model_portal_wizard_user
|
||||
msgid "Portal User Config"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid ""
|
||||
"If the template renders to an empty result in a certain context it will be "
|
||||
"ignored, as if it was inactive."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: field:portal.payment.acquirer,visible:0
|
||||
msgid "Visible"
|
||||
msgstr "ปรากฏเห็น"
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/wizard/share_wizard.py:39
|
||||
#, python-format
|
||||
msgid "Existing Groups (e.g Portal Groups)"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.wizard:0
|
||||
msgid "Cancel"
|
||||
msgstr "ยกเลิก"
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.wizard:0
|
||||
msgid "Apply"
|
||||
msgstr "ใช้งาน"
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "ctx: the current context dictionary"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid ""
|
||||
"This is an HTML form template to submit a payment through this acquirer.\n"
|
||||
" The template will be rendered with"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: code:addons/portal/mail_mail.py:42
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Access your personal documents through <a href=\"%s\">our Customer Portal</a>"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: view:portal.payment.acquirer:0
|
||||
msgid "Form Template"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal
|
||||
#: model:ir.actions.act_window,name:portal.partner_wizard_action
|
||||
#: model:ir.model,name:portal.model_portal_wizard
|
||||
#: view:portal.wizard:0
|
||||
msgid "Portal Access Management"
|
||||
msgstr ""
|
|
@ -0,0 +1,25 @@
|
|||
# English (Australia) translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-06-24 01:47+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: English (Australia) <en_AU@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-25 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: portal_anonymous
|
||||
#. openerp-web
|
||||
#: code:addons/portal_anonymous/static/src/xml/portal_anonymous.xml:8
|
||||
#, python-format
|
||||
msgid "Login"
|
||||
msgstr "Login"
|
|
@ -0,0 +1,25 @@
|
|||
# Thai translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-06-20 14:03+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Thai <th@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-21 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: portal_anonymous
|
||||
#. openerp-web
|
||||
#: code:addons/portal_anonymous/static/src/xml/portal_anonymous.xml:8
|
||||
#, python-format
|
||||
msgid "Login"
|
||||
msgstr "เข้าระบบ"
|
|
@ -0,0 +1,546 @@
|
|||
# Thai translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-06-20 14:52+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Thai <th@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-21 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,type:0
|
||||
msgid "Lead"
|
||||
msgstr "ผู้นำ"
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,title:0
|
||||
msgid "Title"
|
||||
msgstr "คำนำหน้าชื่อ"
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,probability:0
|
||||
msgid "Success Rate (%)"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: view:portal_crm.crm_contact_us:0
|
||||
msgid "Contact us"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,date_action:0
|
||||
msgid "Next Action Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,fax:0
|
||||
msgid "Fax"
|
||||
msgstr "โทรสาร"
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,zip:0
|
||||
msgid "Zip"
|
||||
msgstr "รหัสไปรษณีย์"
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,message_unread:0
|
||||
msgid "Unread Messages"
|
||||
msgstr "ข้อความที่ยังไม่ได้อ่าน"
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,company_id:0
|
||||
msgid "Company"
|
||||
msgstr "บริษัท"
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,day_open:0
|
||||
msgid "Days to Open"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: view:portal_crm.crm_contact_us:0
|
||||
msgid "Thank you for your interest, we'll respond to your request shortly."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,priority:0
|
||||
msgid "Highest"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,mobile:0
|
||||
msgid "Mobile"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,description:0
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,message_ids:0
|
||||
msgid "Messages"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,color:0
|
||||
msgid "Color Index"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,partner_latitude:0
|
||||
msgid "Geo Latitude"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,partner_name:0
|
||||
msgid "Customer Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,state:0
|
||||
msgid "Cancelled"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,message_unread:0
|
||||
msgid "If checked new messages require your attention."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,channel_id:0
|
||||
msgid "Communication channel (mail, direct, phone, ...)"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,type_id:0
|
||||
msgid "Campaign"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,ref:0
|
||||
msgid "Reference"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,date_action_next:0
|
||||
#: field:portal_crm.crm_contact_us,title_action:0
|
||||
msgid "Next Action"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,message_summary:0
|
||||
msgid ""
|
||||
"Holds the Chatter summary (number of messages, ...). This summary is "
|
||||
"directly in html format in order to be inserted in kanban views."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,partner_id:0
|
||||
msgid "Partner"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: model:ir.actions.act_window,name:portal_crm.action_contact_us
|
||||
msgid "Contact Us"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,name:0
|
||||
msgid "Subject"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,opt_out:0
|
||||
msgid "Opt-Out"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,priority:0
|
||||
msgid "Priority"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,state_id:0
|
||||
msgid "State"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,message_follower_ids:0
|
||||
msgid "Followers"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,partner_id:0
|
||||
msgid "Linked partner (optional). Usually created when converting the lead."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,payment_mode:0
|
||||
msgid "Payment Mode"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,state:0
|
||||
msgid "New"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,type:0
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,email_from:0
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,channel_id:0
|
||||
msgid "Channel"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: view:portal_crm.crm_contact_us:0
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,priority:0
|
||||
msgid "Lowest"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,create_date:0
|
||||
msgid "Creation Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: view:portal_crm.crm_contact_us:0
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,state:0
|
||||
msgid "Pending"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,type:0
|
||||
msgid "Type is used to separate Leads and Opportunities"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,categ_ids:0
|
||||
msgid "Categories"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,stage_id:0
|
||||
msgid "Stage"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,user_login:0
|
||||
msgid "User Login"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,opt_out:0
|
||||
msgid ""
|
||||
"If opt-out is checked, this contact has refused to receive emails or "
|
||||
"unsubscribed to a campaign."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,contact_name:0
|
||||
msgid "Contact Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: model:ir.ui.menu,name:portal_crm.portal_company_contact
|
||||
msgid "Contact"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,partner_address_email:0
|
||||
msgid "Partner Contact Email"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,planned_revenue:0
|
||||
msgid "Expected Revenue"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,task_ids:0
|
||||
msgid "Tasks"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: view:portal_crm.crm_contact_us:0
|
||||
msgid "Contact form"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,company_currency:0
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,write_date:0
|
||||
msgid "Update Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,date_deadline:0
|
||||
msgid "Expected Closing"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,ref2:0
|
||||
msgid "Reference 2"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,user_email:0
|
||||
msgid "User Email"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,date_open:0
|
||||
msgid "Opened"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,state:0
|
||||
msgid "In Progress"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,partner_name:0
|
||||
msgid ""
|
||||
"The name of the future partner company that will be created while converting "
|
||||
"the lead into opportunity"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,planned_cost:0
|
||||
msgid "Planned Costs"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,date_deadline:0
|
||||
msgid "Estimate of the date on which the opportunity will be won."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,email_cc:0
|
||||
msgid ""
|
||||
"These email addresses will be added to the CC field of all inbound and "
|
||||
"outbound emails for this record before being sent. Separate multiple email "
|
||||
"addresses with a comma"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,priority:0
|
||||
msgid "Low"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,date_closed:0
|
||||
#: selection:portal_crm.crm_contact_us,state:0
|
||||
msgid "Closed"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,date_assign:0
|
||||
msgid "Assignation Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,state:0
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,priority:0
|
||||
msgid "Normal"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,email_cc:0
|
||||
msgid "Global CC"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,street2:0
|
||||
msgid "Street2"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,id:0
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,phone:0
|
||||
msgid "Phone"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,message_is_follower:0
|
||||
msgid "Is a Follower"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,active:0
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,user_id:0
|
||||
msgid "Salesperson"
|
||||
msgstr "พนักงานขาย"
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,day_close:0
|
||||
msgid "Days to Close"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,company_ids:0
|
||||
msgid "Companies"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,message_summary:0
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,section_id:0
|
||||
msgid ""
|
||||
"When sending mails, the default email address is taken from the sales team."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,partner_address_name:0
|
||||
msgid "Partner Contact Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,partner_longitude:0
|
||||
msgid "Geo Longitude"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,date_assign:0
|
||||
msgid "Last date this case was forwarded/assigned to a partner"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,email_from:0
|
||||
msgid "Email address of the contact"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,city:0
|
||||
msgid "City"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: view:portal_crm.crm_contact_us:0
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,function:0
|
||||
msgid "Function"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,referred:0
|
||||
msgid "Referred By"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,partner_assigned_id:0
|
||||
msgid "Assigned Partner"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,type:0
|
||||
msgid "Opportunity"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,partner_assigned_id:0
|
||||
msgid "Partner this case has been forwarded/assigned to."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,country_id:0
|
||||
msgid "Country"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: view:portal_crm.crm_contact_us:0
|
||||
msgid "Thank you"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,state:0
|
||||
msgid ""
|
||||
"The Status is set to 'Draft', when a case is created. If the case is in "
|
||||
"progress the Status is set to 'Open'. When the case is over, the Status is "
|
||||
"set to 'Done'. If the case needs to be reviewed then the Status is set to "
|
||||
"'Pending'."
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,message_ids:0
|
||||
msgid "Messages and communication history"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: help:portal_crm.crm_contact_us,type_id:0
|
||||
msgid ""
|
||||
"From which campaign (seminar, marketing campaign, mass mailing, ...) did "
|
||||
"this contact come from?"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: selection:portal_crm.crm_contact_us,priority:0
|
||||
msgid "High"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,section_id:0
|
||||
msgid "Sales Team"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,street:0
|
||||
msgid "Street"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: field:portal_crm.crm_contact_us,date_action_last:0
|
||||
msgid "Last Action"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_crm
|
||||
#: model:ir.model,name:portal_crm.model_portal_crm_crm_contact_us
|
||||
msgid "Contact form for the portal"
|
||||
msgstr ""
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-TODAY OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -18,5 +18,3 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import event
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-TODAY OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -30,11 +30,13 @@ This module adds event menu and features to your portal if event and portal are
|
|||
==========================================================================================
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['event','portal'],
|
||||
'depends': [
|
||||
'event',
|
||||
'portal',
|
||||
],
|
||||
'data': [
|
||||
'event_view.xml',
|
||||
'security/portal_security.xml',
|
||||
'portal_event_view.xml',
|
||||
'security/portal_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'installable': True,
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- add visibility field to the event form view -->
|
||||
<record id="view_event_form_portal" model="ir.ui.view">
|
||||
<field name="name">portal.event.form</field>
|
||||
<field name="model">event.event</field>
|
||||
<field name="inherit_id" ref="event.view_event_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[last()]" position="after">
|
||||
<page string="Portal Settings" groups="base.group_user">
|
||||
<group>
|
||||
<field name="visibility"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -2,17 +2,21 @@
|
|||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="portal_event_rule" model="ir.rule">
|
||||
<field name="name">Portal Visible Events</field>
|
||||
<field ref="event.model_event_event" name="model_id"/>
|
||||
<field name="domain_force">['|', ('visibility', '=', 'public'), ('message_follower_ids','in', [user.partner_id.id])]</field>
|
||||
<record model="ir.rule" id="event_event_portal_anonymous_rule">
|
||||
<field name="name">Event: portal and anonymous users: public only</field>
|
||||
<field name="model_id" ref="event.model_event_event"/>
|
||||
<field name="domain_force">['|',
|
||||
('visibility', '=', 'public'),
|
||||
('message_follower_ids', 'in', [user.partner_id.id])
|
||||
]
|
||||
</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal')), (4, ref('portal.group_anonymous'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="portal_registration_rule" model="ir.rule">
|
||||
<field name="name">Portal Personal Registrations</field>
|
||||
<field ref="event.model_event_registration" name="model_id"/>
|
||||
<field name="domain_force">[('user_id','=',user.id)]</field>
|
||||
<record model="ir.rule" id="event_registration_portal_anonymous_rule">
|
||||
<field name="name">Event/Registration: portal and anonymous users: personal only</field>
|
||||
<field name="model_id" ref="event.model_event_registration"/>
|
||||
<field name="domain_force">[('user_id', '=', user.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal')), (4, ref('portal.group_anonymous'))]"/>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
# Thai translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-06-20 13:57+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Thai <th@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-21 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16677)\n"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: view:hr.employee:0
|
||||
msgid "Coach"
|
||||
msgstr "โค้ช"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: model:ir.actions.act_window,name:portal_hr_employees.action_team
|
||||
#: view:portal_crm.crm_contact_us:0
|
||||
msgid "Our Team"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: view:hr.employee:0
|
||||
msgid "Group By..."
|
||||
msgstr "จัดกลุ่มตาม..."
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: view:hr.employee:0
|
||||
msgid "Company"
|
||||
msgstr "บริษัท"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: selection:hr.employee,visibility:0
|
||||
msgid "Public"
|
||||
msgstr "สาธารณะ"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: help:hr.employee,visibility:0
|
||||
msgid "Employee's visibility in the portal's contact page"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: selection:hr.employee,visibility:0
|
||||
msgid "Private"
|
||||
msgstr "ส่วนตัว"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: view:hr.employee:0
|
||||
msgid "Manager"
|
||||
msgstr "ผู้จัดการ"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: model:ir.model,name:portal_hr_employees.model_hr_employee
|
||||
msgid "Employee"
|
||||
msgstr "พนักงาน"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: view:hr.employee:0
|
||||
msgid "Job"
|
||||
msgstr "งาน"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: field:hr.employee,visibility:0
|
||||
msgid "Visibility"
|
||||
msgstr "มองเห็นได้"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: field:hr.employee,public_info:0
|
||||
msgid "Public Info"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: model:ir.model,name:portal_hr_employees.model_portal_crm_crm_contact_us
|
||||
msgid "Contact form for the portal"
|
||||
msgstr ""
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: view:hr.employee:0
|
||||
msgid "Department"
|
||||
msgstr "แผนก"
|
||||
|
||||
#. module: portal_hr_employees
|
||||
#: view:hr.employee:0
|
||||
#: field:portal_crm.crm_contact_us,employee_ids:0
|
||||
msgid "Employees"
|
||||
msgstr "พนักงาน"
|
|
@ -30,12 +30,13 @@ This module adds project menu and features (tasks) to your portal if project and
|
|||
======================================================================================================
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['project','portal'],
|
||||
'depends': ['project', 'portal'],
|
||||
'data': [
|
||||
'security/portal_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'portal_project_view.xml',
|
||||
],
|
||||
'demo': [],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
'category': 'Hidden',
|
||||
|
|
|
@ -30,7 +30,7 @@ class portal_project(osv.Model):
|
|||
""" Override to add portal option. """
|
||||
selection = super(portal_project, self)._get_visibility_selection(cr, uid, context=context)
|
||||
idx = [item[0] for item in selection].index('public')
|
||||
selection.insert((idx + 1), ('portal', 'Portal Users and Employees'))
|
||||
selection.insert((idx + 1), ('portal', 'Customer related project: visible through portal'))
|
||||
return selection
|
||||
# return [('public', 'All Users'),
|
||||
# ('portal', 'Portal Users and Employees'),
|
||||
|
|
|
@ -27,12 +27,10 @@ class res_partner(osv.osv):
|
|||
_inherit = 'res.partner'
|
||||
_columns = {
|
||||
'property_product_pricelist': fields.property(
|
||||
'product.pricelist',
|
||||
type='many2one',
|
||||
relation='product.pricelist',
|
||||
domain=[('type','=','sale')],
|
||||
string="Sale Pricelist",
|
||||
view_load=True,
|
||||
help="This pricelist will be used, instead of the default one, for sales to the current partner"),
|
||||
}
|
||||
|
||||
|
|
|
@ -321,7 +321,7 @@ class product_template(osv.osv):
|
|||
'uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True, help="Default Unit of Measure used for all stock operation."),
|
||||
'uom_po_id': fields.many2one('product.uom', 'Purchase Unit of Measure', required=True, help="Default Unit of Measure used for purchase orders. It must be in the same category than the default unit of measure."),
|
||||
'uos_id' : fields.many2one('product.uom', 'Unit of Sale',
|
||||
help='Sepcify a unit of measure here if invoicing is made in another unit of measure than inventory. Keep empty to use the default unit of measure.'),
|
||||
help='Specify a unit of measure here if invoicing is made in another unit of measure than inventory. Keep empty to use the default unit of measure.'),
|
||||
'uos_coeff': fields.float('Unit of Measure -> UOS Coeff', digits_compute= dp.get_precision('Product UoS'),
|
||||
help='Coefficient to convert default Unit of Measure to Unit of Sale\n'
|
||||
' uos = uom * coeff'),
|
||||
|
|
|
@ -7,14 +7,14 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 6.0dev\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
|
||||
"PO-Revision-Date: 2012-12-14 14:12+0000\n"
|
||||
"Last-Translator: sum1201 <Unknown>\n"
|
||||
"PO-Revision-Date: 2013-06-27 03:25+0000\n"
|
||||
"Last-Translator: Alan <shuchuan.wu@gmail.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-03-16 04:57+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-27 05:36+0000\n"
|
||||
"X-Generator: Launchpad (build 16681)\n"
|
||||
|
||||
#. module: project
|
||||
#: view:project.project:0
|
||||
|
@ -82,7 +82,7 @@ msgid "Start Task"
|
|||
msgstr "开始任务"
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:932
|
||||
#: code:addons/project/project.py:944
|
||||
#, python-format
|
||||
msgid "Warning !"
|
||||
msgstr "警告!"
|
||||
|
@ -132,8 +132,8 @@ msgid ""
|
|||
msgstr "保存复杂的摘要(消息数量,……等)。为了插入到看板视图,这一摘要直接是是HTML格式。"
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:432
|
||||
#: code:addons/project/project.py:1318
|
||||
#: code:addons/project/project.py:444
|
||||
#: code:addons/project/project.py:1332
|
||||
#, python-format
|
||||
msgid "Warning!"
|
||||
msgstr "警告!"
|
||||
|
@ -383,7 +383,7 @@ msgid "Assigned to"
|
|||
msgstr "指派到"
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:1021
|
||||
#: code:addons/project/project.py:1033
|
||||
#, python-format
|
||||
msgid "Delegated User should be specified"
|
||||
msgstr "应该制定委派用户"
|
||||
|
@ -433,7 +433,7 @@ msgstr "使用集成的协作记事簿任务"
|
|||
#: model:mail.message.subtype,name:project.mt_project_task_blocked
|
||||
#: model:mail.message.subtype,name:project.mt_task_blocked
|
||||
msgid "Task Blocked"
|
||||
msgstr ""
|
||||
msgstr "延期的任务"
|
||||
|
||||
#. module: project
|
||||
#: model:process.node,note:project.process_node_opentask0
|
||||
|
@ -453,7 +453,7 @@ msgstr "oe_kanban_text_red"
|
|||
#. module: project
|
||||
#: model:mail.message.subtype,description:project.mt_task_blocked
|
||||
msgid "Task blocked"
|
||||
msgstr ""
|
||||
msgstr "延期的任务"
|
||||
|
||||
#. module: project
|
||||
#: view:project.task:0
|
||||
|
@ -866,7 +866,7 @@ msgstr "公司"
|
|||
#. module: project
|
||||
#: field:project.task.type,fold:0
|
||||
msgid "Folded by Default"
|
||||
msgstr ""
|
||||
msgstr "默认折叠"
|
||||
|
||||
#. module: project
|
||||
#: field:project.task.history,date:0
|
||||
|
@ -1195,9 +1195,9 @@ msgid "Computed as: Time Spent + Remaining Time."
|
|||
msgstr "计算:花费的时间 + 剩余的时间"
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:356
|
||||
#: code:addons/project/project.py:377
|
||||
#: code:addons/project/project.py:709
|
||||
#: code:addons/project/project.py:368
|
||||
#: code:addons/project/project.py:389
|
||||
#: code:addons/project/project.py:721
|
||||
#, python-format
|
||||
msgid "%s (copy)"
|
||||
msgstr "%s (副本)"
|
||||
|
@ -1397,7 +1397,7 @@ msgid ""
|
|||
msgstr "做任务的估计时间.通常由项目经理在任务草稿阶段设定"
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:220
|
||||
#: code:addons/project/project.py:230
|
||||
#, python-format
|
||||
msgid "Attachments"
|
||||
msgstr "附件"
|
||||
|
@ -1447,7 +1447,7 @@ msgstr "剩余的小时数"
|
|||
#. module: project
|
||||
#: model:mail.message.subtype,description:project.mt_task_stage
|
||||
msgid "Stage changed"
|
||||
msgstr ""
|
||||
msgstr "任务阶段已改变"
|
||||
|
||||
#. module: project
|
||||
#: constraint:project.task:0
|
||||
|
@ -1524,7 +1524,7 @@ msgid "Overpassed Tasks"
|
|||
msgstr "拖期任务"
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:932
|
||||
#: code:addons/project/project.py:944
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Child task still open.\n"
|
||||
|
@ -1556,7 +1556,7 @@ msgstr "委派你的任务给其它用户"
|
|||
#. module: project
|
||||
#: model:mail.message.subtype,description:project.mt_task_started
|
||||
msgid "Task started"
|
||||
msgstr ""
|
||||
msgstr "已开始的任务"
|
||||
|
||||
#. module: project
|
||||
#: help:project.task.reevaluate,remaining_hours:0
|
||||
|
@ -1585,7 +1585,7 @@ msgid "CHECK: "
|
|||
msgstr "CHECK: "
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:432
|
||||
#: code:addons/project/project.py:444
|
||||
#, python-format
|
||||
msgid "You must assign members on the project '%s' !"
|
||||
msgstr "您必须为项目“%s”指定成员!"
|
||||
|
@ -1811,7 +1811,7 @@ msgid "Starting Date"
|
|||
msgstr "开始日期"
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:398
|
||||
#: code:addons/project/project.py:410
|
||||
#: model:ir.actions.act_window,name:project.open_view_project_all
|
||||
#: model:ir.ui.menu,name:project.menu_projects
|
||||
#: view:project.project:0
|
||||
|
@ -1972,7 +1972,7 @@ msgid "Reevaluation Task"
|
|||
msgstr "任务重估"
|
||||
|
||||
#. module: project
|
||||
#: code:addons/project/project.py:1318
|
||||
#: code:addons/project/project.py:1332
|
||||
#, python-format
|
||||
msgid "Please delete the project linked with this account first."
|
||||
msgstr "请删除与此科目关联的项目"
|
||||
|
|
|
@ -182,10 +182,10 @@ class project(osv.osv):
|
|||
_('You cannot delete a project containing tasks. You can either delete all the project\'s tasks and then delete the project or simply deactivate the project.'))
|
||||
elif proj.alias_id:
|
||||
alias_ids.append(proj.alias_id.id)
|
||||
res = super(project, self).unlink(cr, uid, ids, context=context)
|
||||
res = super(project, self).unlink(cr, uid, ids, context=context)
|
||||
mail_alias.unlink(cr, uid, alias_ids, context=context)
|
||||
return res
|
||||
|
||||
|
||||
def _get_attached_docs(self, cr, uid, ids, field_name, arg, context):
|
||||
res = {}
|
||||
attachment = self.pool.get('ir.attachment')
|
||||
|
@ -196,7 +196,7 @@ class project(osv.osv):
|
|||
task_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)], context=context, count=True)
|
||||
res[id] = (project_attachments or 0) + (task_attachments or 0)
|
||||
return res
|
||||
|
||||
|
||||
def _task_count(self, cr, uid, ids, field_name, arg, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
@ -209,22 +209,21 @@ class project(osv.osv):
|
|||
return res
|
||||
|
||||
def _get_alias_models(self, cr, uid, context=None):
|
||||
"""Overriden in project_issue to offer more options"""
|
||||
""" Overriden in project_issue to offer more options """
|
||||
return [('project.task', "Tasks")]
|
||||
|
||||
def _get_visibility_selection(self, cr, uid, context=None):
|
||||
""" Overriden in portal_project to offer more options """
|
||||
return [('public', 'Public'),
|
||||
('employees', 'Employees Only'),
|
||||
('followers', 'Followers Only')]
|
||||
return [('public', 'Public project'),
|
||||
('employees', 'Internal project: all employees can access'),
|
||||
('followers', 'Private project: followers Only')]
|
||||
|
||||
def attachment_tree_view(self, cr, uid, ids, context):
|
||||
task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)])
|
||||
domain = [
|
||||
'|',
|
||||
'|',
|
||||
'&', ('res_model', '=', 'project.project'), ('res_id', 'in', ids),
|
||||
'&', ('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)
|
||||
]
|
||||
'&', ('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)]
|
||||
res_id = ids and ids[0] or False
|
||||
return {
|
||||
'name': _('Attachments'),
|
||||
|
@ -237,6 +236,7 @@ class project(osv.osv):
|
|||
'limit': 80,
|
||||
'context': "{'default_res_model': '%s','default_res_id': %d}" % (self._name, res_id)
|
||||
}
|
||||
|
||||
# Lambda indirection method to avoid passing a copy of the overridable method when declaring the field
|
||||
_alias_models = lambda self, *args, **kwargs: self._get_alias_models(*args, **kwargs)
|
||||
_visibility_selection = lambda self, *args, **kwargs: self._get_visibility_selection(*args, **kwargs)
|
||||
|
@ -370,13 +370,11 @@ class project(osv.osv):
|
|||
default['state'] = 'open'
|
||||
default['line_ids'] = []
|
||||
default['tasks'] = []
|
||||
default.pop('alias_name', None)
|
||||
default.pop('alias_id', None)
|
||||
proj = self.browse(cr, uid, id, context=context)
|
||||
if not default.get('name', False):
|
||||
default.update(name=_("%s (copy)") % (proj.name))
|
||||
res = super(project, self).copy(cr, uid, id, default, context)
|
||||
self.map_tasks(cr,uid,id,res,context)
|
||||
self.map_tasks(cr, uid, id, res, context=context)
|
||||
return res
|
||||
|
||||
def duplicate_template(self, cr, uid, ids, context=None):
|
||||
|
@ -527,7 +525,7 @@ def Project():
|
|||
for project in projects:
|
||||
project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,))
|
||||
for task in project.tasks:
|
||||
if task.state in ('done','cancelled'):
|
||||
if task.state in ('done', 'cancelled'):
|
||||
continue
|
||||
|
||||
p = getattr(project_gantt, 'Task_%d' % (task.id,))
|
||||
|
@ -547,23 +545,18 @@ def Project():
|
|||
# ------------------------------------------------
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if context is None: context = {}
|
||||
# Prevent double project creation when 'use_tasks' is checked!
|
||||
context = dict(context, project_creation_in_progress=True)
|
||||
mail_alias = self.pool.get('mail.alias')
|
||||
if not vals.get('alias_id') and vals.get('name', False):
|
||||
alias_name = vals.pop('alias_name', None) # prevent errors during copy()
|
||||
alias_id = mail_alias.create_unique_alias(cr, uid,
|
||||
# Using '+' allows using subaddressing for those who don't
|
||||
# have a catchall domain setup.
|
||||
{'alias_name': alias_name or "project+"+short_name(vals['name'])},
|
||||
model_name=vals.get('alias_model', 'project.task'),
|
||||
context=context)
|
||||
vals['alias_id'] = alias_id
|
||||
if vals.get('type', False) not in ('template','contract'):
|
||||
if context is None:
|
||||
context = {}
|
||||
# Prevent double project creation when 'use_tasks' is checked + alias management
|
||||
create_context = dict(context, project_creation_in_progress=True,
|
||||
alias_model_name=vals.get('alias_model', 'project.task'), alias_parent_model_name=self._name)
|
||||
|
||||
if vals.get('type', False) not in ('template', 'contract'):
|
||||
vals['type'] = 'contract'
|
||||
project_id = super(project, self).create(cr, uid, vals, context)
|
||||
mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'project_id': project_id} }, context)
|
||||
|
||||
project_id = super(project, self).create(cr, uid, vals, context=create_context)
|
||||
project_rec = self.browse(cr, uid, project_id, context=context)
|
||||
self.pool.get('mail.alias').write(cr, uid, [project_rec.alias_id.id], {'alias_parent_thread_id': project_id, 'alias_defaults': {'project_id': project_id}}, context)
|
||||
return project_id
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
|
|
|
@ -46,9 +46,12 @@
|
|||
<record id="project_project_2" model="project.project">
|
||||
<field name="name">Research & Development</field>
|
||||
<field name="parent_id" ref="all_projects_account"/>
|
||||
<field name="privacy_visibility">public</field>
|
||||
<field name="privacy_visibility">followers</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="alias_model">project.task</field>
|
||||
<field name="message_follower_ids" eval="[(6, 0, [
|
||||
ref('base.user_root'),
|
||||
ref('base.user_demo')])]"/>
|
||||
</record>
|
||||
|
||||
<!-- We assign after so that default values applies -->
|
||||
|
@ -75,6 +78,7 @@
|
|||
<field name="parent_id" ref="all_projects_account"/>
|
||||
<field name="name">Website Design Templates</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="privacy_visibility">followers</field>
|
||||
<field name="alias_model">project.task</field>
|
||||
<field name="privacy_visibility">employees</field>
|
||||
<field name="members" eval="[(4, ref('base.user_root')), (4,ref('base.user_demo'))]"/>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue