diff --git a/addons/account/account.py b/addons/account/account.py
index caf1d68c45d..571ea40698d 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -1862,8 +1862,10 @@ class account_tax(osv.osv):
'applicable_type': fields.selection( [('true','Always'), ('code','Given by Python Code')], 'Applicability', required=True,
help="If not applicable (computed through a Python code), the tax won't appear on the invoice."),
'domain':fields.char('Domain', size=32, help="This field is only used if you develop your own module allowing developers to create specific taxes in a custom domain."),
- 'account_collected_id':fields.many2one('account.account', 'Invoice Tax Account'),
- 'account_paid_id':fields.many2one('account.account', 'Refund Tax Account'),
+ 'account_collected_id':fields.many2one('account.account', 'Invoice Tax Account', help="Set the account that will be set by default on invoice tax lines for invoices. Leave empty to use the expense account."),
+ 'account_paid_id':fields.many2one('account.account', 'Refund Tax Account', help="Set the account that will be set by default on invoice tax lines for refunds. Leave empty to use the expense account."),
+ 'account_analytic_collected_id':fields.many2one('account.analytic.account', 'Invoice Tax Analytic Account', help="Set the analytic account that will be used by default on the invoice tax lines for invoices. Leave empty if you don't want to use an analytic account on the invoice tax lines by default."),
+ 'account_analytic_paid_id':fields.many2one('account.analytic.account', 'Refund Tax Analytic Account', help="Set the analytic account that will be used by default on the invoice tax lines for refunds. Leave empty if you don't want to use an analytic account on the invoice tax lines by default."),
'parent_id':fields.many2one('account.tax', 'Parent Tax Account', select=True),
'child_ids':fields.one2many('account.tax', 'parent_id', 'Child Tax Accounts'),
'child_depend':fields.boolean('Tax on Children', help="Set if the tax computation is based on the computation of child taxes rather than on the total amount."),
@@ -2001,6 +2003,8 @@ class account_tax(osv.osv):
'name':tax.description and tax.description + " - " + tax.name or tax.name,
'account_collected_id':tax.account_collected_id.id,
'account_paid_id':tax.account_paid_id.id,
+ 'account_analytic_collected_id': tax.account_analytic_collected_id.id,
+ 'account_analytic_paid_id': tax.account_analytic_paid_id.id,
'base_code_id': tax.base_code_id.id,
'ref_base_code_id': tax.ref_base_code_id.id,
'sequence': tax.sequence,
@@ -2066,7 +2070,20 @@ class account_tax(osv.osv):
'taxes': [] # List of taxes, see compute for the format
}
"""
+
+ # By default, for each tax, tax amount will first be computed
+ # and rounded at the 'Account' decimal precision for each
+ # PO/SO/invoice line and then these rounded amounts will be
+ # summed, leading to the total amount for that tax. But, if the
+ # company has tax_calculation_rounding_method = round_globally,
+ # we still follow the same method, but we use a much larger
+ # precision when we round the tax amount for each line (we use
+ # the 'Account' decimal precision + 5), and that way it's like
+ # rounding after the sum of the tax amounts of each line
precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
+ tax_compute_precision = precision
+ if taxes and taxes[0].company_id.tax_calculation_rounding_method == 'round_globally':
+ tax_compute_precision += 5
totalin = totalex = round(price_unit * quantity, precision)
tin = []
tex = []
@@ -2075,7 +2092,7 @@ class account_tax(osv.osv):
tex.append(tax)
else:
tin.append(tax)
- tin = self.compute_inv(cr, uid, tin, price_unit, quantity, product=product, partner=partner)
+ tin = self.compute_inv(cr, uid, tin, price_unit, quantity, product=product, partner=partner, precision=tax_compute_precision)
for r in tin:
totalex -= r.get('amount', 0.0)
totlex_qty = 0.0
@@ -2083,7 +2100,7 @@ class account_tax(osv.osv):
totlex_qty = totalex/quantity
except:
pass
- tex = self._compute(cr, uid, tex, totlex_qty, quantity,product=product, partner=partner)
+ tex = self._compute(cr, uid, tex, totlex_qty, quantity, product=product, partner=partner, precision=tax_compute_precision)
for r in tex:
totalin += r.get('amount', 0.0)
return {
@@ -2096,7 +2113,7 @@ class account_tax(osv.osv):
_logger.warning("Deprecated, use compute_all(...)['taxes'] instead of compute(...) to manage prices with tax included")
return self._compute(cr, uid, taxes, price_unit, quantity, product, partner)
- def _compute(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None):
+ def _compute(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None, precision=None):
"""
Compute tax values for given PRICE_UNIT, QUANTITY and a buyer/seller ADDRESS_ID.
@@ -2105,14 +2122,15 @@ class account_tax(osv.osv):
tax = {'name':'', 'amount':0.0, 'account_collected_id':1, 'account_paid_id':2}
one tax for each tax id in IDS and their children
"""
+ if not precision:
+ precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
res = self._unit_compute(cr, uid, taxes, price_unit, product, partner, quantity)
total = 0.0
- precision_pool = self.pool.get('decimal.precision')
for r in res:
if r.get('balance',False):
- r['amount'] = round(r.get('balance', 0.0) * quantity, precision_pool.precision_get(cr, uid, 'Account')) - total
+ r['amount'] = round(r.get('balance', 0.0) * quantity, precision) - total
else:
- r['amount'] = round(r.get('amount', 0.0) * quantity, precision_pool.precision_get(cr, uid, 'Account'))
+ r['amount'] = round(r.get('amount', 0.0) * quantity, precision)
total += r['amount']
return res
@@ -2160,6 +2178,8 @@ class account_tax(osv.osv):
'amount': amount,
'account_collected_id': tax.account_collected_id.id,
'account_paid_id': tax.account_paid_id.id,
+ 'account_analytic_collected_id': tax.account_analytic_collected_id.id,
+ 'account_analytic_paid_id': tax.account_analytic_paid_id.id,
'base_code_id': tax.base_code_id.id,
'ref_base_code_id': tax.ref_base_code_id.id,
'sequence': tax.sequence,
@@ -2188,7 +2208,7 @@ class account_tax(osv.osv):
r['todo'] = 0
return res
- def compute_inv(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None):
+ def compute_inv(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None, precision=None):
"""
Compute tax values for given PRICE_UNIT, QUANTITY and a buyer/seller ADDRESS_ID.
Price Unit is a VAT included price
@@ -2198,15 +2218,15 @@ class account_tax(osv.osv):
tax = {'name':'', 'amount':0.0, 'account_collected_id':1, 'account_paid_id':2}
one tax for each tax id in IDS and their children
"""
+ if not precision:
+ precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
res = self._unit_compute_inv(cr, uid, taxes, price_unit, product, partner=None)
total = 0.0
- obj_precision = self.pool.get('decimal.precision')
for r in res:
- prec = obj_precision.precision_get(cr, uid, 'Account')
if r.get('balance',False):
- r['amount'] = round(r['balance'] * quantity, prec) - total
+ r['amount'] = round(r['balance'] * quantity, precision) - total
else:
- r['amount'] = round(r['amount'] * quantity, prec)
+ r['amount'] = round(r['amount'] * quantity, precision)
total += r['amount']
return res
diff --git a/addons/account/account_analytic_line.py b/addons/account/account_analytic_line.py
index 280b813380f..06de5a3e43e 100644
--- a/addons/account/account_analytic_line.py
+++ b/addons/account/account_analytic_line.py
@@ -34,8 +34,8 @@ class account_analytic_line(osv.osv):
'journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal', required=True, ondelete='restrict', select=True),
'code': fields.char('Code', size=8),
'ref': fields.char('Ref.', size=64),
- 'currency_id': fields.related('move_id', 'currency_id', type='many2one', relation='res.currency', string='Account currency', store=True, help="The related account currency if not equal to the company one.", readonly=True),
- 'amount_currency': fields.related('move_id', 'amount_currency', type='float', string='Amount currency', store=True, help="The amount expressed in the related account currency if not equal to the company one.", readonly=True),
+ 'currency_id': fields.related('move_id', 'currency_id', type='many2one', relation='res.currency', string='Account Currency', store=True, help="The related account currency if not equal to the company one.", readonly=True),
+ 'amount_currency': fields.related('move_id', 'amount_currency', type='float', string='Amount Currency', store=True, help="The amount expressed in the related account currency if not equal to the company one.", readonly=True),
}
_defaults = {
diff --git a/addons/account/account_bank.py b/addons/account/account_bank.py
index cbc5a966f79..ef146128a67 100644
--- a/addons/account/account_bank.py
+++ b/addons/account/account_bank.py
@@ -43,6 +43,12 @@ class bank(osv.osv):
"Return the name to use when creating a bank journal"
return (bank.bank_name or '') + ' ' + bank.acc_number
+ def _prepare_name_get(self, cr, uid, bank_type_obj, bank_obj, context=None):
+ """Add ability to have %(currency_name)s in the format_layout of
+ res.partner.bank.type"""
+ bank_obj._data[bank_obj.id]['currency_name'] = bank_obj.currency_id and bank_obj.currency_id.name or ''
+ return super(bank, self)._prepare_name_get(cr, uid, bank_type_obj, bank_obj, context=context)
+
def post_write(self, cr, uid, ids, context={}):
if isinstance(ids, (int, long)):
ids = [ids]
diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml
index 73c9652f8fa..8e2526c3f97 100644
--- a/addons/account/account_installer.xml
+++ b/addons/account/account_installer.xml
@@ -13,8 +13,7 @@
Continue
-
-
+
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index c6011979f8d..5e27a2e3663 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -756,7 +756,7 @@ class account_invoice(osv.osv):
for tax in inv.tax_line:
if tax.manual:
continue
- key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id)
+ key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id, tax.account_analytic_id.id)
tax_key.append(key)
if not key in compute_taxes:
raise osv.except_osv(_('Warning !'), _('Global taxes defined, but they are not in invoice lines !'))
@@ -1002,7 +1002,7 @@ class account_invoice(osv.osv):
'quantity': x.get('quantity',1.00),
'product_id': x.get('product_id', False),
'product_uom_id': x.get('uos_id', False),
- 'analytic_account_id': x.get('account_analytic_id', False),
+ 'analytic_account_id': x.get('analytic_account_id', False),
}
def action_number(self, cr, uid, ids, context=None):
@@ -1578,6 +1578,7 @@ class account_invoice_tax(osv.osv):
'invoice_id': fields.many2one('account.invoice', 'Invoice Line', ondelete='cascade', select=True),
'name': fields.char('Tax Description', size=64, required=True),
'account_id': fields.many2one('account.account', 'Tax Account', required=True, domain=[('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')]),
+ 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic account'),
'base': fields.float('Base', digits_compute=dp.get_precision('Account')),
'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),
'manual': fields.boolean('Manual'),
@@ -1648,14 +1649,16 @@ class account_invoice_tax(osv.osv):
val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
val['account_id'] = tax['account_collected_id'] or line.account_id.id
+ val['account_analytic_id'] = tax['account_analytic_collected_id']
else:
val['base_code_id'] = tax['ref_base_code_id']
val['tax_code_id'] = tax['ref_tax_code_id']
val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['ref_base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['ref_tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
val['account_id'] = tax['account_paid_id'] or line.account_id.id
+ val['account_analytic_id'] = tax['account_analytic_paid_id']
- key = (val['tax_code_id'], val['base_code_id'], val['account_id'])
+ key = (val['tax_code_id'], val['base_code_id'], val['account_id'], val['account_analytic_id'])
if not key in tax_grouped:
tax_grouped[key] = val
else:
@@ -1687,7 +1690,8 @@ class account_invoice_tax(osv.osv):
'price': t['amount'] or 0.0,
'account_id': t['account_id'],
'tax_code_id': t['tax_code_id'],
- 'tax_amount': t['tax_amount']
+ 'tax_amount': t['tax_amount'],
+ 'analytic_account_id': t['account_analytic_id'],
})
return res
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index 49bbe8d3a4d..bc964b787c7 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -98,6 +98,7 @@
+
@@ -157,33 +158,39 @@
-
-
-
+
+ 1. Webdav server that provides remote access to calendar
+ 2. Synchronisation of calendar using WebDAV
+ 3. Customize calendar event and todo attribute with any of OpenERP model
+ 4. Provides iCal Import/Export functionality
+
+
+ To access Calendars using CalDAV clients, point them to:
+ http://HOSTNAME:PORT/webdav/DATABASE_NAME/calendars/users/USERNAME/c
+
+ To access OpenERP Calendar using WebCal to remote site use the URL like:
+ http://HOSTNAME:PORT/webdav/DATABASE_NAME/Calendars/CALENDAR_NAME.ics
+
+
+ HOSTNAME: Host on which OpenERP server(With webdav) is running
+ PORT : Port on which OpenERP server is running (By Default : 8069)
+ DATABASE_NAME: Name of database on which OpenERP Calendar is created
+
-
@@ -523,7 +565,7 @@
@@ -535,8 +577,7 @@
crm.leadtree
-
-
+
@@ -555,6 +596,7 @@
+
@@ -567,21 +609,21 @@
search
+
- scheduled on %s.") % (meeting_date_str)
+ # in the message, transpose meeting.date to the timezone of the current user
+ meeting_date = fields.DT.datetime.strptime(meeting.date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
+ meeting_date_tz = fields.datetime.context_timestamp(cr, uid, meeting_date, context=context).strftime(tools.DATETIME_FORMATS_MAP['%+'] + " (%Z)")
if meeting.opportunity_id: # meeting can be create from phonecalls or opportunities, therefore checking for the parent
lead = meeting.opportunity_id
- parent_message = _("Meeting linked to the opportunity %s has been created and cscheduled on %s.") % (lead.name, meeting.date)
+ message = _("Meeting linked to the opportunity %s has been created and scheduled on %s.") % (lead.name, meeting_date_tz)
lead.message_append_note(_('System Notification'), message)
elif meeting.phonecall_id:
phonecall = meeting.phonecall_id
- parent_message = _("Meeting linked to the phonecall %s has been created and cscheduled on %s.") % (phonecall.name, meeting.date)
+ message = _("Meeting linked to the phonecall %s has been created and scheduled on %s.") % (phonecall.name, meeting_date_tz)
phonecall.message_append_note(body=message)
else:
- parent_message = message
- if parent_message:
- meeting.message_append_note(body=parent_message)
+ message = _("A meeting has been scheduled on %s.") % (meeting_date_tz)
+ meeting.message_append_note(body=message)
return True
- def case_open_send_note(self, cr, uid, ids, context=None):
- return self.message_append_note(cr, uid, ids, body=_("Meeting has been confirmed."), context=context)
-
- def case_close_send_note(self, cr, uid, ids, context=None):
- return self.message_append_note(cr, uid, ids, body=_("Meeting has been done."), context=context)
-
-
class calendar_attendee(osv.osv):
""" Calendar Attendee """
@@ -162,8 +98,6 @@ class calendar_attendee(osv.osv):
relation="crm.case.categ", multi='categ_id'),
}
-calendar_attendee()
-
class res_users(osv.osv):
_name = 'res.users'
_inherit = 'res.users'
@@ -184,7 +118,4 @@ class res_users(osv.osv):
_logger.debug('Skipped meetings shortcut for user "%s"', data.get('name','
-
+ Customer Meeting
-
-
-
+ Internal Meeting
-
-
-
+ Phone Call
-
-
diff --git a/addons/crm/crm_meeting_menu.xml b/addons/crm/crm_meeting_menu.xml
index 6c4c9051cbf..aec88a5748e 100644
--- a/addons/crm/crm_meeting_menu.xml
+++ b/addons/crm/crm_meeting_menu.xml
@@ -1,102 +1,9 @@
-
-
-
-
- calendar
-
-
-
-
-
-
- tree
-
-
-
-
-
-
- form
-
-
-
-
-
-
- gantt
-
-
-
-
-
- Meetings
- crm.meeting
- calendar,tree,form,gantt
-
- {"calendar_default_user_id":uid}
-
- The meeting calendar is shared between the sales teams and fully integrated with other applications such as the employee holidays or the business opportunities. You can also synchronize meetings with your mobile phone using the caldav interface.
-
-
-
-
-
- calendar
-
-
-
-
-
-
- tree
-
-
-
-
-
-
- form
-
-
-
-
-
-
- gantt
-
-
-
-
-
-
-
-
- Meeting Invitations
- ir.actions.act_window
- calendar.attendee
- form
- tree,form
-
- [('ref','like','crm.meeting,')]
- {"search_default_toreview":1, "search_default_user_id":uid}
- With Meeting Invitations you can create and manage the meeting invitations sent/to be sent to your colleagues/partners. You can not only invite OpenERP users, but also external parties, such as a customer.
-
-
-
diff --git a/addons/crm/crm_meeting_shortcut_data.xml b/addons/crm/crm_meeting_shortcut_data.xml
index 0f75c9e91ab..45488da8a82 100644
--- a/addons/crm/crm_meeting_shortcut_data.xml
+++ b/addons/crm/crm_meeting_shortcut_data.xml
@@ -6,7 +6,7 @@
Meetingsir.ui.menu
-
+
diff --git a/addons/crm/crm_meeting_view.xml b/addons/crm/crm_meeting_view.xml
index 21c34ff4e9b..f7c2ada05f2 100644
--- a/addons/crm/crm_meeting_view.xml
+++ b/addons/crm/crm_meeting_view.xml
@@ -2,317 +2,48 @@
-
-
-
- Meeting Categories
- crm.case.categ
- form
-
- [('object_id.model', '=', 'crm.meeting')]
-
- Create different meeting categories to better organize and classify your meetings.
-
-
-
-
-
+ CRM - Meetings Formcrm.meetingform
+
-
diff --git a/addons/crm/wizard/crm_lead_to_opportunity_view.xml b/addons/crm/wizard/crm_lead_to_opportunity_view.xml
index a240a4de66c..5ad9ef1c9c9 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity_view.xml
+++ b/addons/crm/wizard/crm_lead_to_opportunity_view.xml
@@ -6,11 +6,6 @@
form
-
-
- or
-
-
@@ -27,6 +22,11 @@
+
@@ -37,11 +37,6 @@
form
-
-
- or
-
-
@@ -53,6 +48,11 @@
+
diff --git a/addons/crm/wizard/crm_lead_to_partner_view.xml b/addons/crm/wizard/crm_lead_to_partner_view.xml
index ce12d62f9bf..a430c943d5d 100644
--- a/addons/crm/wizard/crm_lead_to_partner_view.xml
+++ b/addons/crm/wizard/crm_lead_to_partner_view.xml
@@ -9,16 +9,16 @@
form
-
-
- or
-
-
+
diff --git a/addons/crm/wizard/crm_merge_opportunities_view.xml b/addons/crm/wizard/crm_merge_opportunities_view.xml
index 99de31afc15..74973193f24 100644
--- a/addons/crm/wizard/crm_merge_opportunities_view.xml
+++ b/addons/crm/wizard/crm_merge_opportunities_view.xml
@@ -10,11 +10,6 @@
form
-
-
- or
-
-
@@ -24,6 +19,11 @@
+
diff --git a/addons/crm/wizard/crm_opportunity_to_phonecall_view.xml b/addons/crm/wizard/crm_opportunity_to_phonecall_view.xml
index 6c921b3f071..ccabcde88fe 100644
--- a/addons/crm/wizard/crm_opportunity_to_phonecall_view.xml
+++ b/addons/crm/wizard/crm_opportunity_to_phonecall_view.xml
@@ -10,12 +10,6 @@
form
-
-
-
- or
-
-
@@ -34,6 +28,12 @@
+
diff --git a/addons/crm/wizard/crm_partner_to_opportunity_view.xml b/addons/crm/wizard/crm_partner_to_opportunity_view.xml
index 3f37a0b6fa1..8bc97ba141b 100644
--- a/addons/crm/wizard/crm_partner_to_opportunity_view.xml
+++ b/addons/crm/wizard/crm_partner_to_opportunity_view.xml
@@ -9,17 +9,17 @@
form
-
-
- or
-
-
+
diff --git a/addons/crm/wizard/crm_phonecall_to_meeting.py b/addons/crm/wizard/crm_phonecall_to_meeting.py
index 9e902142c94..a01765220b8 100644
--- a/addons/crm/wizard/crm_phonecall_to_meeting.py
+++ b/addons/crm/wizard/crm_phonecall_to_meeting.py
@@ -41,58 +41,23 @@ class crm_phonecall2meeting(osv.osv_memory):
return {'type':'ir.actions.act_window_close'}
def action_make_meeting(self, cr, uid, ids, context=None):
+ """ This opens Meeting's calendar view to schedule meeting on current Phonecall
+ @return : Dictionary value for created Meeting view
"""
- This opens Meeting's calendar view to schedule meeting on current Phonecall
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks,
- @param ids: List of Phonecall to Meeting IDs
- @param context: A standard dictionary for contextual values
-
- @return : Dictionary value for created Meeting view
- """
- value = {}
- record_id = context and context.get('active_id', False) or False
-
- if record_id:
- phonecall_obj = self.pool.get('crm.phonecall')
- data_obj = self.pool.get('ir.model.data')
-
- # Get meeting views
- result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
- res = data_obj.read(cr, uid, result, ['res_id'])
- id1 = data_obj._get_id(cr, uid, 'crm', 'crm_case_calendar_view_meet')
- id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_meet')
- id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_meet')
- if id1:
- id1 = data_obj.browse(cr, uid, id1, context=context).res_id
- if id2:
- id2 = data_obj.browse(cr, uid, id2, context=context).res_id
- if id3:
- id3 = data_obj.browse(cr, uid, id3, context=context).res_id
-
- phonecall = phonecall_obj.browse(cr, uid, record_id, context=context)
- context = {
- 'default_phonecall_id': phonecall.id,
- 'default_partner_id': phonecall.partner_id and phonecall.partner_id.id or False,
- 'default_email': phonecall.email_from ,
- 'default_name': phonecall.name
- }
-
- value = {
- 'name': _('Meetings'),
- 'domain' : "[('user_id','=',%s)]" % (uid),
- 'context': context,
- 'view_type': 'form',
- 'view_mode': 'calendar,form,tree',
- 'res_model': 'crm.meeting',
- 'view_id': False,
- 'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
- 'type': 'ir.actions.act_window',
- 'search_view_id': res['res_id']
- }
-
- return value
+ res = {}
+ phonecall_id = context and context.get('active_id', False) or False
+ if phonecall_id:
+ phonecall = self.pool.get('crm.phonecall').browse(cr, uid, phonecall_id, context)
+ res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'base_calendar', 'action_crm_meeting', context)
+ res['context'] = {
+ 'default_phonecall_id': phonecall.id,
+ 'default_partner_id': phonecall.partner_id and phonecall.partner_id.id or False,
+ 'default_user_id': uid,
+ 'default_email_from': phonecall.email_from,
+ 'default_state': 'open',
+ 'default_name': phonecall.name,
+ }
+ return res
crm_phonecall2meeting()
diff --git a/addons/crm/wizard/crm_phonecall_to_meeting_view.xml b/addons/crm/wizard/crm_phonecall_to_meeting_view.xml
index 85d0bf4bc47..00f6700e5a5 100644
--- a/addons/crm/wizard/crm_phonecall_to_meeting_view.xml
+++ b/addons/crm/wizard/crm_phonecall_to_meeting_view.xml
@@ -11,13 +11,13 @@
form
-
+
+
-
+
diff --git a/addons/crm/wizard/crm_phonecall_to_opportunity_view.xml b/addons/crm/wizard/crm_phonecall_to_opportunity_view.xml
index 1dc14786cc3..5304bd8beb5 100644
--- a/addons/crm/wizard/crm_phonecall_to_opportunity_view.xml
+++ b/addons/crm/wizard/crm_phonecall_to_opportunity_view.xml
@@ -10,17 +10,17 @@
form
-
-
- or
-
-
+
diff --git a/addons/crm/wizard/crm_phonecall_to_partner_view.xml b/addons/crm/wizard/crm_phonecall_to_partner_view.xml
index 3281acdeec3..1243d7bc456 100644
--- a/addons/crm/wizard/crm_phonecall_to_partner_view.xml
+++ b/addons/crm/wizard/crm_phonecall_to_partner_view.xml
@@ -9,14 +9,14 @@
form
-
-
- or
-
-
+
@@ -29,15 +29,15 @@
form
-
-
- or
-
-
+
diff --git a/addons/crm/wizard/crm_phonecall_to_phonecall_view.xml b/addons/crm/wizard/crm_phonecall_to_phonecall_view.xml
index a9819d63886..25f7dd0ba81 100644
--- a/addons/crm/wizard/crm_phonecall_to_phonecall_view.xml
+++ b/addons/crm/wizard/crm_phonecall_to_phonecall_view.xml
@@ -10,23 +10,20 @@
form
-
-
-
- or
-
-
-
-
-
+
diff --git a/addons/crm/wizard/mail_compose_message.py b/addons/crm/wizard/mail_compose_message.py
deleted file mode 100644
index b82c3083f3a..00000000000
--- a/addons/crm/wizard/mail_compose_message.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2010-Today OpenERP SA ()
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see
-#
-##############################################################################
-
-from osv import osv
-from osv import fields
-import tools
-
-SUPPORTED_MODELS = ['crm.lead',]
-
-class mail_compose_message(osv.osv_memory):
- _inherit = 'mail.compose.message'
-
- def get_value(self, cr, uid, model, res_id, context=None):
- """Returns a defaults-like dict with initial values for the composition
- wizard when sending an email related to the document record identified
- by ``model`` and ``res_id``.
-
- Overrides the default implementation to provide more default field values
- related to the corresponding CRM case.
-
- :param str model: model name of the document record this mail is related to.
- :param int res_id: id of the document record this mail is related to.
- :param dict context: several context values will modify the behavior
- of the wizard, cfr. the class description.
- """
- result = super(mail_compose_message, self).get_value(cr, uid, model, res_id, context=context)
- if model in SUPPORTED_MODELS and res_id:
- model_obj = self.pool.get(model)
- data = model_obj.browse(cr, uid , res_id, context)
- user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
- result.update({
- 'subject' : data.name or False,
- 'email_to' : data.email_from or False,
- 'email_from' : user.user_email or tools.config.get('email_from', False),
- 'body_text' : '\n' + tools.ustr(user.signature or ''),
- 'email_cc' : tools.ustr(data.email_cc or ''),
- 'model': model,
- 'res_id': res_id,
- 'subtype': 'plain',
- })
- if hasattr(data, 'section_id'):
- result.update({'reply_to' : data.section_id and data.section_id.reply_to or False})
- return result
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm_caldav/crm_caldav_setup.xml b/addons/crm_caldav/crm_caldav_setup.xml
index 7e20a318e4f..36f3c3fd78b 100644
--- a/addons/crm_caldav/crm_caldav_setup.xml
+++ b/addons/crm_caldav/crm_caldav_setup.xml
@@ -29,7 +29,7 @@
[('user_id','=', dctx_user_id)]vevent
-
+
@@ -103,7 +103,7 @@
-
+ field
@@ -127,7 +127,7 @@
-
+ field
@@ -163,7 +163,7 @@
-
+ {'tentative': 'draft', 'confirmed': 'open', 'cancelled': 'cancel'}field
@@ -176,7 +176,7 @@
-
+ datetime_utc
diff --git a/addons/crm_caldav/crm_caldav_view.xml b/addons/crm_caldav/crm_caldav_view.xml
index 287e301532e..5746a3af0aa 100644
--- a/addons/crm_caldav/crm_caldav_view.xml
+++ b/addons/crm_caldav/crm_caldav_view.xml
@@ -2,7 +2,7 @@
- Caldav Browse
+ Synchronize Your Meetingsir.actions.act_windowuser.preference
diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py
index 808ad2e2055..ec6252bcdca 100644
--- a/addons/crm_claim/crm_claim.py
+++ b/addons/crm_claim/crm_claim.py
@@ -22,14 +22,11 @@
from base_status.base_stage import base_stage
import binascii
from crm import crm
-from crm import wizard
from osv import fields, osv
import time
import tools
from tools.translate import _
-wizard.mail_compose_message.SUPPORTED_MODELS.append('crm.claim')
-
CRM_CLAIM_PENDING_STATES = (
crm.AVAILABLE_STATES[2][0], # Cancelled
crm.AVAILABLE_STATES[3][0], # Done
@@ -75,6 +72,7 @@ class crm_claim(base_stage, osv.osv):
_description = "Claim"
_order = "priority,date desc"
_inherit = ['mail.thread']
+ _mail_compose_message = True
_columns = {
'id': fields.integer('ID', readonly=True),
'name': fields.char('Claim Subject', size=128, required=True),
@@ -183,59 +181,53 @@ class crm_claim(base_stage, osv.osv):
}
address = self.pool.get('res.partner').browse(cr, uid, part)
return {'value': {'email_from': address.email, 'partner_phone': address.phone}}
-
- def message_new(self, cr, uid, msg, custom_values=None, context=None):
- """Automatically called when new email message arrives"""
- res_id = super(crm_claim,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
- subject = msg.get('subject')
- body = msg.get('body_text')
- msg_from = msg.get('from')
- priority = msg.get('priority')
- vals = {
- 'name': subject,
- 'email_from': msg_from,
- 'email_cc': msg.get('cc'),
- 'description': body,
- 'user_id': False,
- }
- if priority:
- vals['priority'] = priority
- vals.update(self.message_partner_by_email(cr, uid, msg.get('from', False)))
- self.write(cr, uid, [res_id], vals, context=context)
- return res_id
- def message_update(self, cr, uid, ids, msg, vals={}, default_act='pending', context=None):
+ # -------------------------------------------------------
+ # Mail gateway
+ # -------------------------------------------------------
+
+ def message_new(self, cr, uid, msg, custom_values=None, context=None):
+ """ Overrides mail_thread message_new that is called by the mailgateway
+ through message_process.
+ This override updates the document according to the email.
+ """
+ if custom_values is None: custom_values = {}
+ custom_values.update({
+ 'name': msg.get('subject') or _("No Subject"),
+ 'description': msg.get('body_text'),
+ 'email_from': msg.get('from'),
+ 'email_cc': msg.get('cc'),
+ })
+ if msg.get('priority'):
+ custom_values['priority'] = msg.get('priority')
+ custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from'), context=context))
+ return super(crm_claim,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
+
+ def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
+ """ Overrides mail_thread message_update that is called by the mailgateway
+ through message_process.
+ This method updates the document according to the email.
+ """
if isinstance(ids, (str, int, long)):
ids = [ids]
-
- res_id = super(crm_claim,self).message_update(cr, uid, ids, msg, context=context)
+ if update_vals is None: update_vals = {}
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
- vals['priority'] = msg.get('priority')
+ update_vals['priority'] = msg.get('priority')
maps = {
'cost':'planned_cost',
'revenue': 'planned_revenue',
'probability':'probability'
}
- vls = {}
for line in msg['body_text'].split('\n'):
line = line.strip()
res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower()):
key = maps.get(res.group(1).lower())
- vls[key] = res.group(2).lower()
- vals.update(vls)
+ update_vals[key] = res.group(2).lower()
- # Unfortunately the API is based on lists
- # but we want to update the state based on the
- # previous state, so we have to loop:
- for case in self.browse(cr, uid, ids, context=context):
- values = dict(vals)
- if case.state in CRM_CLAIM_PENDING_STATES:
- values.update(state=crm.AVAILABLE_STATES[1][0]) #re-open
- res = self.write(cr, uid, [case.id], values, context=context)
- return res
+ return super(crm_claim,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)
# ---------------------------------------------------
# OpenChatter methods and notifications
diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml
index 5c6e66de076..cf803fe6384 100644
--- a/addons/crm_claim/crm_claim_view.xml
+++ b/addons/crm_claim/crm_claim_view.xml
@@ -168,9 +168,9 @@
-
diff --git a/addons/lunch/wizard/lunch_cashbox_clean_view.xml b/addons/lunch/wizard/lunch_cashbox_clean_view.xml
index 287d283e212..eb05c0dc304 100644
--- a/addons/lunch/wizard/lunch_cashbox_clean_view.xml
+++ b/addons/lunch/wizard/lunch_cashbox_clean_view.xml
@@ -10,14 +10,14 @@
form
-
-
- or
-
-
+
diff --git a/addons/lunch/wizard/lunch_order_cancel_view.xml b/addons/lunch/wizard/lunch_order_cancel_view.xml
index cd96b9765c9..cb10eb57fd0 100644
--- a/addons/lunch/wizard/lunch_order_cancel_view.xml
+++ b/addons/lunch/wizard/lunch_order_cancel_view.xml
@@ -10,14 +10,14 @@
form
-
-
- or
-
-
+
diff --git a/addons/lunch/wizard/lunch_order_confirm_view.xml b/addons/lunch/wizard/lunch_order_confirm_view.xml
index ade5b227cc2..282b79539f8 100644
--- a/addons/lunch/wizard/lunch_order_confirm_view.xml
+++ b/addons/lunch/wizard/lunch_order_confirm_view.xml
@@ -10,15 +10,15 @@
form
-
-
- or
-
-
+
diff --git a/addons/mail/__init__.py b/addons/mail/__init__.py
index d9835f86fc5..805c27386f3 100644
--- a/addons/mail/__init__.py
+++ b/addons/mail/__init__.py
@@ -23,6 +23,7 @@ import mail_message
import mail_thread
import mail_group
import mail_subscription
+import ir_needaction
import res_users
import res_partner
import report
diff --git a/addons/mail/__openerp__.py b/addons/mail/__openerp__.py
index 95ce7d5619d..e911f24e809 100644
--- a/addons/mail/__openerp__.py
+++ b/addons/mail/__openerp__.py
@@ -20,36 +20,41 @@
##############################################################################
{
- 'name': 'Emails Management',
+ 'name': 'Social Network',
'version': '1.0',
- 'category': 'Hidden/Dependency',
+ 'category':'Social Network',
+ "sequence": 2,
'description': """
-A generic email subsystem with message storage and queuing
-==========================================================
+A bussiness oriented Social Networking with a fully-integrated email
+and message management.
+=====================================================================
+The Social Networking module provides an unified social network
+abstraction layer allowing applications to display a complete
+communication history on documents.It gives the users the possibility
+to read and send messages and emails in an unified way.
-This email subsystem is not intended to be used as as standalone
-application, but to provide a unified email abstraction that all
-other applications can use.
+It also provides a feeds page combined to a subscription mechanism, that
+allows to follow documents, and to be constantly updated about recent
+news.
+
+The main features of the module are :
-The main features are:
-
- * Relies on the global Outgoing Mail Servers configured in the
- Administration menu for delivering outgoing mail
- * Provides an API for sending messages and archiving them,
- grouped by conversation
- * Any OpenERP document can act as a conversation topic, provided
- it includes the necessary support for handling incoming emails
- (see the ``mail.thread`` class for more details).
- * Includes queuing mechanism with automated configurable
- scheduler-based processing
- * Includes a generic email composition assistant, that can turn
+ * a clean and renewed communication history for any OpenERP
+ document that can act as a discussion topic,
+ * a discussion mean on documents,
+ * a subscription mechanism to be updated about new messages on
+ interesting documents,
+ * an unified feeds page to see recent messages and activity
+ on followed documents,
+ * user communication through the feeds page,
+ * a threaded discussion design,
+ * relies on the global outgoing mail server, an integrated email
+ management system allowing to send emails with a configurable
+ scheduler-based processing engine
+ * includes an extensible generic email composition assistant, that can turn
into a mass-mailing assistant, and is capable of interpreting
simple *placeholder expressions* that will be replaced with
- dynamic data when each email is actually sent.
- This generic assistant is easily extensible to provide advanced
- features (see ``email_template`` for example, which adds email
- templating features to this assistant)
-
+ dynamic data when each email is actually sent
""",
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
@@ -69,6 +74,7 @@ The main features are:
],
'installable': True,
'auto_install': False,
+ 'application':True,
'certificate': '001056784984222247309',
'images': [
'images/customer_history.jpeg',
@@ -86,6 +92,7 @@ The main features are:
'static/src/css/mail_group.css',
],
'js': [
+ 'static/lib/jquery.expander/jquery.expander.js',
'static/src/js/mail.js',
],
'qweb': [
@@ -93,6 +100,6 @@ The main features are:
],
'demo': [
'mail_demo.xml',
- ],
+ ],
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail/doc/index.rst.inc b/addons/mail/doc/index.rst.inc
index 822d855d5b4..c4b87cc18f9 100644
--- a/addons/mail/doc/index.rst.inc
+++ b/addons/mail/doc/index.rst.inc
@@ -10,3 +10,4 @@ Mail Module documentation topics
mail_openchatter_howto
mail_needaction_howto
mail_partner
+ mail_state
diff --git a/addons/mail/doc/mail_openchatter_howto.rst b/addons/mail/doc/mail_openchatter_howto.rst
index 7ca52348d99..4c8797e7f8b 100644
--- a/addons/mail/doc/mail_openchatter_howto.rst
+++ b/addons/mail/doc/mail_openchatter_howto.rst
@@ -38,7 +38,7 @@ Make your module inheriting from the ``mail.thread`` class.
# inherit from mail.thread allows the use of OpenChatter
_inherit = ['mail.thread']
-Use the thread viewer widget inside your form view by using the ThreadView widget on the message_ids field inherited from mail.thread.
+Use the thread viewer widget inside your form view by using the mail_thread widget on the message_ids field inherited from mail.thread.
::
@@ -50,7 +50,7 @@ Use the thread viewer widget inside your form view by using the ThreadView widge
[...]
-
+
@@ -131,7 +131,7 @@ The drawback of this method is that it is no longer possible to those subscriber
Messages display management
++++++++++++++++++++++++++++
-By default, the ThreadView widget shows all messages related to the current document beside the document, in the History and comments section. However, you may want to display other messages in the widget. For example, the OpenChatter on res.users model shows
+By default, the mail_thread widget shows all messages related to the current document beside the document, in the History and comments section. However, you may want to display other messages in the widget. For example, the OpenChatter on res.users model shows
- messages related to the user, as usual (messages with ``model = res.users, res_id = current_document_id``)
- messages directly pushed to this user (containing @login)
diff --git a/addons/mail/doc/mail_state.rst b/addons/mail/doc/mail_state.rst
new file mode 100644
index 00000000000..527a31ba835
--- /dev/null
+++ b/addons/mail/doc/mail_state.rst
@@ -0,0 +1,28 @@
+.. _mail_state:
+
+message_state
+=============
+
+``message_state`` is a boolean field that states whether the document
+has unread messages. In previous versions, some documents were going
+back to ``pending`` state when receiving an email through the mail
+gateway. Now the state related to messages differs from the state or
+stage of the document itself.
+
+message_state and need action mechanism
++++++++++++++++++++++++++++++++++++++++
+
+The ``mail`` module introduces a default behavior for the need_action
+mechanism [REF].
+
+::
+
+ def get_needaction_user_ids(self, cr, uid, ids, context=None):
+ """ Returns the user_ids that have to perform an action
+ :return: dict { record_id: [user_ids], }
+ """
+ result = super(ir_needaction_mixin, self).get_needaction_user_ids(cr, uid, ids, context=context)
+ for obj in self.browse(cr, uid, ids, context=context):
+ if obj.message_state == False and obj.user_id:
+ result[obj.id].append(obj.user_id.id)
+ return result
diff --git a/addons/mail/ir_needaction.py b/addons/mail/ir_needaction.py
new file mode 100644
index 00000000000..8193ac4f385
--- /dev/null
+++ b/addons/mail/ir_needaction.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2012-today OpenERP SA ()
+#
+# 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
+#
+##############################################################################
+
+from osv import osv
+
+class ir_needaction_mixin(osv.Model):
+ """ Update of ir.needaction_mixin class
+ - override the get_needaction_user_ids method to define the default
+ mail gateway need_action: when the object is unread, the object
+ responsible has an action to perform.
+ """
+ _name = 'ir.needaction_mixin'
+ _inherit = ['ir.needaction_mixin']
+
+ def get_needaction_user_ids(self, cr, uid, ids, context=None):
+ """ Returns the user_ids that have to perform an action. It the
+ document mail state is unread (False), return object.user_id.id
+ as need_action uid.
+ :return: dict { record_id: [user_ids], }
+ """
+ result = super(ir_needaction_mixin, self).get_needaction_user_ids(cr, uid, ids, context=context)
+ for obj in self.browse(cr, uid, ids, context=context):
+ if obj.message_state == False and obj.user_id:
+ result[obj.id].append(obj.user_id.id)
+ return result
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py
index 0a8677d7862..f691d75e0bc 100644
--- a/addons/mail/mail_group.py
+++ b/addons/mail/mail_group.py
@@ -87,7 +87,7 @@ class mail_group(osv.osv):
result = dict.fromkeys(ids)
for id in ids:
result[id] = {}
- result[id]['member_ids'] = self.message_get_subscribers_ids(cr, uid, [id], context=context)
+ result[id]['member_ids'] = self.message_get_subscribers(cr, uid, [id], context=context)
result[id]['member_count'] = len(result[id]['member_ids'])
result[id]['is_subscriber'] = uid in result[id]['member_ids']
return result
diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml
index 921c3b528c4..6ad1792b3b4 100644
--- a/addons/mail/mail_group_view.xml
+++ b/addons/mail/mail_group_view.xml
@@ -51,28 +51,30 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index 1c1e980e3ed..301657ba4c2 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -96,11 +96,24 @@ class mail_message_common(osv.osv_memory):
continue
result[message.id] = self.pool.get(message.model).name_get(cr, uid, [message.res_id], context=context)[0][1]
return result
-
+
+ def name_get(self, cr, uid, ids, context=None):
+ res = []
+ for message in self.browse(cr, uid, ids, context=context):
+ name = ''
+ if message.subject:
+ name = '%s: ' % (message.subject)
+ if message.body_text:
+ name = '%s%s ' % (name, message.body_text[0:20])
+ if message.date:
+ name = '%s(%s)' % (name, message.date)
+ res.append((message.id, name))
+ return res
+
_name = 'mail.message.common'
_rec_name = 'subject'
_columns = {
- 'subject': fields.char('Subject', size=512, required=True),
+ 'subject': fields.char('Subject', size=512),
'model': fields.char('Related Document Model', size=128, select=1),
'res_id': fields.integer('Related Document ID', select=1),
'record_name': fields.function(get_record_name, type='string', string='Message Record Name',
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index e0f2bfaf455..cdcaf4f464d 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -34,7 +34,7 @@ import xmlrpclib
_logger = logging.getLogger(__name__)
-class mail_thread(osv.osv):
+class mail_thread(osv.Model):
'''Mixin model, meant to be inherited by any model that needs to
act as a discussion topic on which messages can be attached.
Public methods are prefixed with ``message_`` in order to avoid
@@ -62,10 +62,15 @@ class mail_thread(osv.osv):
_name = 'mail.thread'
_description = 'Email Thread'
- def _get_message_ids(self, cr, uid, ids, name, arg, context=None):
+ def _get_message_ids(self, cr, uid, ids, name, args, context=None):
res = {}
for id in ids:
- res[id] = self.message_load_ids(cr, uid, [id], context=context)
+ message_ids = self.message_load_ids(cr, uid, [id], context=context)
+ subscriber_ids = self.message_get_subscribers(cr, uid, [id], context=context)
+ res[id] = {
+ 'message_ids': message_ids,
+ 'message_summary': "9 %d+ %d" % (len(message_ids), len(subscriber_ids)),
+ }
return res
def _search_message_ids(self, cr, uid, obj, name, args, context=None):
@@ -73,10 +78,23 @@ class mail_thread(osv.osv):
msg_ids = msg_obj.search(cr, uid, ['&', ('res_id', 'in', args[0][2]), ('model', '=', self._name)], context=context)
return [('id', 'in', msg_ids)]
- # OpenChatter: message_ids is a dummy field that should not be used
_columns = {
- 'message_ids': fields.function(_get_message_ids, method=True, fnct_search=_search_message_ids,
- type='one2many', obj='mail.message', string='Temp messages', _fields_id = 'res_id'),
+ 'message_ids': fields.function(_get_message_ids, method=True,
+ fnct_search=_search_message_ids,
+ type='one2many', obj='mail.message', _fields_id = 'res_id',
+ string='Temp messages', multi="_get_message_ids",
+ help="Functional field holding messages related to the current document."),
+ 'message_state': fields.boolean('Read',
+ help="When checked, new messages require your attention."),
+ 'message_summary': fields.function(_get_message_ids, method=True,
+ type='text', string='Summary', multi="_get_message_ids",
+ help="Holds the Chatter summary (number of messages, ...). "\
+ "This summary is directly in html format in order to "\
+ "be inserted in kanban views."),
+ }
+
+ _defaults = {
+ 'message_state': True,
}
#------------------------------------------------------
@@ -84,10 +102,11 @@ class mail_thread(osv.osv):
#------------------------------------------------------
def create(self, cr, uid, vals, context=None):
- """Automatically subscribe the creator"""
- thread_id = super(mail_thread, self).create(cr, uid, vals, context=context);
- self.message_subscribe(cr, uid, [thread_id], [uid], context=context)
- return thread_id;
+ """Automatically subscribe the creator """
+ thread_id = super(mail_thread, self).create(cr, uid, vals, context=context)
+ if thread_id:
+ self.message_subscribe(cr, uid, [thread_id], [uid], context=context)
+ return thread_id
def write(self, cr, uid, ids, vals, context=None):
"""Automatically subscribe the writer"""
@@ -106,8 +125,6 @@ class mail_thread(osv.osv):
a foreign key with a 'cascade' ondelete attribute.
Notifications will be deleted with messages
"""
- if context is None:
- context = {}
subscr_obj = self.pool.get('mail.subscription')
msg_obj = self.pool.get('mail.message')
# delete subscriptions
@@ -120,17 +137,18 @@ class mail_thread(osv.osv):
return super(mail_thread, self).unlink(cr, uid, ids, context=context)
#------------------------------------------------------
- # Generic message api
+ # mail.message wrappers and tools
#------------------------------------------------------
def message_create(self, cr, uid, thread_id, vals, context=None):
- """OpenSocial: wrapper of mail.message create method
+ """ OpenChatter: wrapper of mail.message create method
- creates the mail.message
- automatically subscribe the message writer
- push the message to subscribed users
"""
if context is None:
context = {}
+
message_obj = self.pool.get('mail.message')
subscription_obj = self.pool.get('mail.subscription')
notification_obj = self.pool.get('mail.notification')
@@ -167,7 +185,10 @@ class mail_thread(osv.osv):
# create message
msg_id = message_obj.create(cr, uid, vals, context=context)
-
+
+ # Set as unread if writer is not the document responsible
+ self.message_create_set_unread(cr, uid, [thread_id], context=context)
+
# special: if install mode, do not push demo data
if context.get('install_mode', False):
return True
@@ -186,7 +207,7 @@ class mail_thread(osv.osv):
body = new_msg_vals.get('body_html', '') if new_msg_vals.get('subtype', 'plain') == 'html' else new_msg_vals.get('body_text', '')
for thread_id in thread_ids:
# add subscribers
- notif_user_ids += [user['id'] for user in self.message_get_subscribers(cr, uid, [thread_id], context=context)]
+ notif_user_ids += self.message_get_subscribers(cr, uid, [thread_id], context=context)
# add users requested via parsing message (@login)
notif_user_ids += self.message_parse_users(cr, uid, [thread_id], body, context=context)
# add users requested to perform an action (need_action mechanism)
@@ -214,6 +235,10 @@ class mail_thread(osv.osv):
user_ids = self.pool.get('res.users').search(cr, uid, [('login', 'in', login_lst)], context=context)
return user_ids
+ #------------------------------------------------------
+ # Generic message api
+ #------------------------------------------------------
+
def message_capable_models(self, cr, uid, context=None):
ret_dict = {}
for model_name in self.pool.obj_list():
@@ -376,7 +401,6 @@ class mail_thread(osv.osv):
original = msg_dict.get('original'),
context = context)
- # Message loading
def _message_add_ancestor_ids(self, cr, uid, ids, child_ids, root_ids, context=None):
""" Given message child_ids
Find their ancestors until root ids"""
@@ -420,6 +444,9 @@ class mail_thread(osv.osv):
msg_ids = self.message_load_ids(cr, uid, ids, limit, offset, domain, ascent, root_ids, context=context)
msgs = self.pool.get('mail.message').read(cr, uid, msg_ids, [], context=context)
+ # Set as read
+ self.message_check_and_set_read(cr, uid, ids, context=context)
+
""" Retrieve all attachments names """
map_id_to_name = {}
@@ -474,7 +501,7 @@ class mail_thread(osv.osv):
return msgs
#------------------------------------------------------
- # Email specific
+ # Mail gateway
#------------------------------------------------------
# message_process will call either message_new or message_update.
@@ -549,7 +576,7 @@ class mail_thread(osv.osv):
if res_id:
res_id = res_id.group(1)
if res_id:
- res_id = int(res_id)
+ res_id = res_id
if model_pool.exists(cr, uid, res_id):
if hasattr(model_pool, 'message_update'):
model_pool.message_update(cr, uid, [res_id], msg, {}, context=context)
@@ -558,7 +585,7 @@ class mail_thread(osv.osv):
res_id = False
if not res_id:
res_id = create_record(msg)
- #To forward the email to other followers
+ # To forward the email to other followers
self.message_forward(cr, uid, model, [res_id], msg_txt, context=context)
return res_id
@@ -594,29 +621,34 @@ class mail_thread(osv.osv):
fields = model_pool.fields_get(cr, uid, context=context)
data = model_pool.default_get(cr, uid, fields, context=context)
if 'name' in fields and not data.get('name'):
- data['name'] = msg_dict.get('from','')
+ data['name'] = msg_dict.get('from', '')
if custom_values and isinstance(custom_values, dict):
data.update(custom_values)
res_id = model_pool.create(cr, uid, data, context=context)
self.message_append_dict(cr, uid, [res_id], msg_dict, context=context)
return res_id
- def message_update(self, cr, uid, ids, msg_dict, vals={}, default_act=None, context=None):
- """Called by ``message_process`` when a new message is received
- for an existing thread. The default behavior is to create a
- new mail.message in the given thread (by calling
- ``message_append_dict``)
- Additional behavior may be implemented by overriding this
- method.
+ def message_update(self, cr, uid, ids, msg_dict, update_vals=None, context=None):
+ """ Called by ``message_process`` when a new message is received
+ for an existing thread. The default behavior is to create a
+ new mail.message in the given thread (by calling
+ ``message_append_dict``)
+ Additional behavior may be implemented by overriding this
+ method.
- :param dict msg_dict: a map containing the email details and
+ :param dict msg_dict: a map containing the email details and
attachments. See ``message_process`` and
``mail.message.parse()`` for details.
- :param dict context: if a ``thread_model`` value is present
+ :param dict vals: a dict containing values to update records
+ given their ids; if the dict is None or is
+ void, no write operation is performed.
+ :param dict context: if a ``thread_model`` value is present
in the context, its value will be used
to determine the model of the thread to
update (instead of the current model).
"""
+ if update_vals:
+ self.write(cr, uid, ids, update_vals, context=context)
return self.message_append_dict(cr, uid, ids, msg_dict, context=context)
def message_thread_followers(self, cr, uid, ids, context=None):
@@ -746,13 +778,8 @@ class mail_thread(osv.osv):
self.message_append_note(cr, uid, [id], 'res.log', message, context=context)
def message_append_note(self, cr, uid, ids, subject=None, body=None, parent_id=False, type='notification', subtype='html', context=None):
- if subject is None:
- if type == 'notification':
- subject = _('System notification')
- elif type == 'comment' and not parent_id:
- subject = _('Comment')
- elif type == 'comment' and parent_id:
- subject = _('Reply')
+ if type in ['notification', 'reply']:
+ subject = None
if subtype == 'html':
body_html = body
body_text = body
@@ -765,51 +792,77 @@ class mail_thread(osv.osv):
# Subscription mechanism
#------------------------------------------------------
- def message_get_subscribers_ids(self, cr, uid, ids, context=None):
+ def message_get_subscribers(self, cr, uid, ids, context=None):
+ """ Returns the current document followers. Basically this method
+ checks in mail.subscription for entries with matching res_model,
+ res_id.
+
+ :param get_ids: if set to True, return the ids of users; if set
+ to False, returns the result of a read in res.users
+ """
subscr_obj = self.pool.get('mail.subscription')
subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context)
- subs = subscr_obj.read(cr, uid, subscr_ids, context=context)
- return [sub['user_id'][0] for sub in subs]
+ return [sub['user_id'][0] for sub in subscr_obj.read(cr, uid, subscr_ids, ['user_id'], context=context)]
- def message_get_subscribers(self, cr, uid, ids, context=None):
- user_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context)
- users = self.pool.get('res.users').read(cr, uid, user_ids, fields=['id', 'name', 'avatar'], context=context)
- return users
+ def message_read_subscribers(self, cr, uid, ids, fields=['id', 'name', 'avatar'], context=None):
+ """ Returns the current document followers as a read result. Used
+ mainly for Chatter having only one method to call to have
+ details about users.
+ """
+ user_ids = self.message_get_subscribers(cr, uid, ids, context=context)
+ return self.pool.get('res.users').read(cr, uid, user_ids, fields=fields, context=context)
def message_is_subscriber(self, cr, uid, ids, user_id = None, context=None):
- users = self.message_get_subscribers(cr, uid, ids, context=context)
+ """ Check if uid or user_id (if set) is a subscriber to the current
+ document.
+
+ :param user_id: if set, check is done on user_id; if not set
+ check is done on uid
+ """
sub_user_id = uid if user_id is None else user_id
- if sub_user_id in [user['id'] for user in users]:
+ if sub_user_id in self.message_get_subscribers(cr, uid, ids, context=context):
return True
return False
def message_subscribe(self, cr, uid, ids, user_ids = None, context=None):
+ """ Subscribe the user (or user_ids) to the current document.
+
+ :param user_ids: a list of user_ids; if not set, subscribe
+ uid instead
+ """
subscription_obj = self.pool.get('mail.subscription')
to_subscribe_uids = [uid] if user_ids is None else user_ids
create_ids = []
for id in ids:
+ already_subscribed_user_ids = self.message_get_subscribers(cr, uid, [id], context=context)
for user_id in to_subscribe_uids:
- if self.message_is_subscriber(cr, uid, [id], user_id=user_id, context=context): continue
+ if user_id in already_subscribed_user_ids: continue
create_ids.append(subscription_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context))
return create_ids
def message_unsubscribe(self, cr, uid, ids, user_ids = None, context=None):
- if not user_ids and not uid in self.message_get_subscribers_ids(cr, uid, ids, context=context):
+ """ Unsubscribe the user (or user_ids) from the current document.
+
+ :param user_ids: a list of user_ids; if not set, subscribe
+ uid instead
+ """
+ # Trying to unsubscribe somebody not in subscribers: returns False
+ # if special management is needed; allows to know that an automatically
+ # subscribed user tries to unsubscribe and allows to warn him
+ mail_thread_model = self.pool.get('mail.thread')
+ if not user_ids and not uid in mail_thread_model.message_get_subscribers(cr, uid, ids, context=context):
return False
subscription_obj = self.pool.get('mail.subscription')
to_unsubscribe_uids = [uid] if user_ids is None else user_ids
to_delete_sub_ids = subscription_obj.search(cr, uid,
['&', '&', ('res_model', '=', self._name), ('res_id', 'in', ids), ('user_id', 'in', to_unsubscribe_uids)], context=context)
- subscription_obj.unlink(cr, uid, to_delete_sub_ids, context=context)
- return True
+ return subscription_obj.unlink(cr, uid, to_delete_sub_ids, context=context)
#------------------------------------------------------
# Notification API
#------------------------------------------------------
def message_remove_pushed_notifications(self, cr, uid, ids, msg_ids, remove_childs=True, context=None):
- if context is None:
- context = {}
notif_obj = self.pool.get('mail.notification')
msg_obj = self.pool.get('mail.message')
if remove_childs:
@@ -819,4 +872,37 @@ class mail_thread(osv.osv):
to_del_notif_ids = notif_obj.search(cr, uid, ['&', ('user_id', '=', uid), ('message_id', 'in', notif_msg_ids)], context=context)
return notif_obj.unlink(cr, uid, to_del_notif_ids, context=context)
+ #------------------------------------------------------
+ # Thread_state
+ #------------------------------------------------------
+
+ def message_create_set_unread(self, cr, uid, ids, context=None):
+ """ When creating a new message, set as unread if uid is not the
+ object responsible. """
+ for obj in self.browse(cr, uid, ids, context=context):
+ if obj.message_state and hasattr(obj, 'user_id') and (not obj.user_id or obj.user_id.id != uid):
+ self.message_mark_as_unread(cr, uid, [obj.id], context=context)
+
+ def message_check_and_set_unread(self, cr, uid, ids, context=None):
+ """ Set unread if uid is the object responsible or if the object has
+ no responsible. """
+ for obj in self.browse(cr, uid, ids, context=context):
+ if obj.message_state and hasattr(obj, 'user_id') and (not obj.user_id or obj.user_id.id == uid):
+ self.message_mark_as_unread(cr, uid, [obj.id], context=context)
+
+ def message_mark_as_unread(self, cr, uid, ids, context=None):
+ """ Set as unread. """
+ return self.write(cr, uid, ids, {'message_state': False}, context=context)
+
+ def message_check_and_set_read(self, cr, uid, ids, context=None):
+ """ Set read if uid is the object responsible. """
+ for obj in self.browse(cr, uid, ids, context=context):
+ if not obj.message_state and hasattr(obj, 'user_id') and obj.user_id and obj.user_id.id == uid:
+ self.message_mark_as_read(cr, uid, [obj.id], context=context)
+
+ def message_mark_as_read(self, cr, uid, ids, context=None):
+ """ Set as read. """
+ return self.write(cr, uid, ids, {'message_state': True}, context=context)
+
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail/res_partner_view.xml b/addons/mail/res_partner_view.xml
index 0a9860dc979..15f6618c8e5 100644
--- a/addons/mail/res_partner_view.xml
+++ b/addons/mail/res_partner_view.xml
@@ -10,7 +10,7 @@
diff --git a/addons/mail/res_users_view.xml b/addons/mail/res_users_view.xml
index 428f53d092e..918f77e0ace 100644
--- a/addons/mail/res_users_view.xml
+++ b/addons/mail/res_users_view.xml
@@ -28,7 +28,7 @@
-
+
diff --git a/addons/mail/static/lib/jquery.expander/jquery.expander.js b/addons/mail/static/lib/jquery.expander/jquery.expander.js
new file mode 100644
index 00000000000..91cc03db918
--- /dev/null
+++ b/addons/mail/static/lib/jquery.expander/jquery.expander.js
@@ -0,0 +1,385 @@
+/*!
+ * jQuery Expander Plugin v1.4.2
+ *
+ * Date: Fri Mar 16 14:29:56 2012 EDT
+ * Requires: jQuery v1.3+
+ *
+ * Copyright 2011, Karl Swedberg
+ * Dual licensed under the MIT and GPL licenses (just like jQuery):
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ *
+ *
+ *
+*/
+
+(function($) {
+ $.expander = {
+ version: '1.4.2',
+ defaults: {
+ // the number of characters at which the contents will be sliced into two parts.
+ slicePoint: 100,
+
+ // whether to keep the last word of the summary whole (true) or let it slice in the middle of a word (false)
+ preserveWords: true,
+
+ // a threshold of sorts for whether to initially hide/collapse part of the element's contents.
+ // If after slicing the contents in two there are fewer words in the second part than
+ // the value set by widow, we won't bother hiding/collapsing anything.
+ widow: 4,
+
+ // text displayed in a link instead of the hidden part of the element.
+ // clicking this will expand/show the hidden/collapsed text
+ expandText: 'read more',
+ expandPrefix: '… ',
+
+ expandAfterSummary: false,
+
+ // class names for summary element and detail element
+ summaryClass: 'summary',
+ detailClass: 'details',
+
+ // class names for around "read-more" link and "read-less" link
+ moreClass: 'read-more',
+ lessClass: 'read-less',
+
+ // number of milliseconds after text has been expanded at which to collapse the text again.
+ // when 0, no auto-collapsing
+ collapseTimer: 0,
+
+ // effects for expanding and collapsing
+ expandEffect: 'fadeIn',
+ expandSpeed: 250,
+ collapseEffect: 'fadeOut',
+ collapseSpeed: 200,
+
+ // allow the user to re-collapse the expanded text.
+ userCollapse: true,
+
+ // text to use for the link to re-collapse the text
+ userCollapseText: 'read less',
+ userCollapsePrefix: ' ',
+
+
+ // all callback functions have the this keyword mapped to the element in the jQuery set when .expander() is called
+
+ onSlice: null, // function() {}
+ beforeExpand: null, // function() {},
+ afterExpand: null, // function() {},
+ onCollapse: null // function(byUser) {}
+ }
+ };
+
+ $.fn.expander = function(options) {
+ var meth = 'init';
+
+ if (typeof options == 'string') {
+ meth = options;
+ options = {};
+ }
+
+ var opts = $.extend({}, $.expander.defaults, options),
+ rSelfClose = /^<(?:area|br|col|embed|hr|img|input|link|meta|param).*>$/i,
+ rAmpWordEnd = opts.wordEnd || /(&(?:[^;]+;)?|[a-zA-Z\u00C0-\u0100]+)$/,
+ rOpenCloseTag = /<\/?(\w+)[^>]*>/g,
+ rOpenTag = /<(\w+)[^>]*>/g,
+ rCloseTag = /<\/(\w+)>/g,
+ rLastCloseTag = /(<\/[^>]+>)\s*$/,
+ rTagPlus = /^<[^>]+>.?/,
+ delayedCollapse;
+
+ var methods = {
+ init: function() {
+ this.each(function() {
+ var i, l, tmp, newChar, summTagless, summOpens, summCloses,
+ lastCloseTag, detailText, detailTagless,
+ $thisDetails, $readMore,
+ openTagsForDetails = [],
+ closeTagsForsummaryText = [],
+ defined = {},
+ thisEl = this,
+ $this = $(this),
+ $summEl = $([]),
+ o = $.meta ? $.extend({}, opts, $this.data()) : opts,
+ hasDetails = !!$this.find('.' + o.detailClass).length,
+ hasBlocks = !!$this.find('*').filter(function() {
+ var display = $(this).css('display');
+ return (/^block|table|list/).test(display);
+ }).length,
+ el = hasBlocks ? 'div' : 'span',
+ detailSelector = el + '.' + o.detailClass,
+ moreSelector = 'span.' + o.moreClass,
+ expandSpeed = o.expandSpeed || 0,
+ allHtml = $.trim( $this.html() ),
+ allText = $.trim( $this.text() ),
+ summaryText = allHtml.slice(0, o.slicePoint);
+
+ // bail out if we've already set up the expander on this element
+ if ( $.data(this, 'expander') ) {
+ return;
+ }
+
+ $.data(this, 'expander', true);
+
+ // determine which callback functions are defined
+ $.each(['onSlice','beforeExpand', 'afterExpand', 'onCollapse'], function(index, val) {
+ defined[val] = $.isFunction(o[val]);
+ });
+
+ // back up if we're in the middle of a tag or word
+ summaryText = backup(summaryText);
+
+ // summary text sans tags length
+ summTagless = summaryText.replace(rOpenCloseTag, '').length;
+
+ // add more characters to the summary, one for each character in the tags
+ while (summTagless < o.slicePoint) {
+ newChar = allHtml.charAt(summaryText.length);
+ if (newChar == '<') {
+ newChar = allHtml.slice(summaryText.length).match(rTagPlus)[0];
+ }
+ summaryText += newChar;
+ summTagless++;
+ }
+
+ summaryText = backup(summaryText, o.preserveWords);
+
+ // separate open tags from close tags and clean up the lists
+ summOpens = summaryText.match(rOpenTag) || [];
+ summCloses = summaryText.match(rCloseTag) || [];
+
+ // filter out self-closing tags
+ tmp = [];
+ $.each(summOpens, function(index, val) {
+ if ( !rSelfClose.test(val) ) {
+ tmp.push(val);
+ }
+ });
+ summOpens = tmp;
+
+ // strip close tags to just the tag name
+ l = summCloses.length;
+ for (i = 0; i < l; i++) {
+ summCloses[i] = summCloses[i].replace(rCloseTag, '$1');
+ }
+
+ // tags that start in summary and end in detail need:
+ // a). close tag at end of summary
+ // b). open tag at beginning of detail
+ $.each(summOpens, function(index, val) {
+ var thisTagName = val.replace(rOpenTag, '$1');
+ var closePosition = $.inArray(thisTagName, summCloses);
+ if (closePosition === -1) {
+ openTagsForDetails.push(val);
+ closeTagsForsummaryText.push('' + thisTagName + '>');
+
+ } else {
+ summCloses.splice(closePosition, 1);
+ }
+ });
+
+ // reverse the order of the close tags for the summary so they line up right
+ closeTagsForsummaryText.reverse();
+
+ // create necessary summary and detail elements if they don't already exist
+ if ( !hasDetails ) {
+
+ // end script if there is no detail text or if detail has fewer words than widow option
+ detailText = allHtml.slice(summaryText.length);
+ detailTagless = $.trim( detailText.replace(rOpenCloseTag, '') );
+
+ if ( detailTagless === '' || detailTagless.split(/\s+/).length < o.widow ) {
+ return;
+ }
+ // otherwise, continue...
+ lastCloseTag = closeTagsForsummaryText.pop() || '';
+ summaryText += closeTagsForsummaryText.join('');
+ detailText = openTagsForDetails.join('') + detailText;
+
+ } else {
+ // assume that even if there are details, we still need readMore/readLess/summary elements
+ // (we already bailed out earlier when readMore el was found)
+ // but we need to create els differently
+
+ // remove the detail from the rest of the content
+ detailText = $this.find(detailSelector).remove().html();
+
+ // The summary is what's left
+ summaryText = $this.html();
+
+ // allHtml is the summary and detail combined (this is needed when content has block-level elements)
+ allHtml = summaryText + detailText;
+
+ lastCloseTag = '';
+ }
+ o.moreLabel = $this.find(moreSelector).length ? '' : buildMoreLabel(o);
+
+ if (hasBlocks) {
+ detailText = allHtml;
+ }
+ summaryText += lastCloseTag;
+
+ // onSlice callback
+ o.summary = summaryText;
+ o.details = detailText;
+ o.lastCloseTag = lastCloseTag;
+
+ if (defined.onSlice) {
+ // user can choose to return a modified options object
+ // one last chance for user to change the options. sneaky, huh?
+ // but could be tricky so use at your own risk.
+ tmp = o.onSlice.call(thisEl, o);
+
+ // so, if the returned value from the onSlice function is an object with a details property, we'll use that!
+ o = tmp && tmp.details ? tmp : o;
+ }
+
+ // build the html with summary and detail and use it to replace old contents
+ var html = buildHTML(o, hasBlocks);
+
+ $this.html( html );
+
+ // set up details and summary for expanding/collapsing
+ $thisDetails = $this.find(detailSelector);
+ $readMore = $this.find(moreSelector);
+ $thisDetails.hide();
+ $readMore.find('a').unbind('click.expander').bind('click.expander', expand);
+
+ $summEl = $this.find('div.' + o.summaryClass);
+
+ if ( o.userCollapse && !$this.find('span.' + o.lessClass).length ) {
+ $this
+ .find(detailSelector)
+ .append('' + o.userCollapsePrefix + '' + o.userCollapseText + '');
+ }
+
+ $this
+ .find('span.' + o.lessClass + ' a')
+ .unbind('click.expander')
+ .bind('click.expander', function(event) {
+ event.preventDefault();
+ clearTimeout(delayedCollapse);
+ var $detailsCollapsed = $(this).closest(detailSelector);
+ reCollapse(o, $detailsCollapsed);
+ if (defined.onCollapse) {
+ o.onCollapse.call(thisEl, true);
+ }
+ });
+
+ function expand(event) {
+ event.preventDefault();
+ $readMore.hide();
+ $summEl.hide();
+ if (defined.beforeExpand) {
+ o.beforeExpand.call(thisEl);
+ }
+
+ $thisDetails.stop(false, true)[o.expandEffect](expandSpeed, function() {
+ $thisDetails.css({zoom: ''});
+ if (defined.afterExpand) {o.afterExpand.call(thisEl);}
+ delayCollapse(o, $thisDetails, thisEl);
+ });
+ }
+
+ }); // this.each
+ },
+ destroy: function() {
+ if ( !this.data('expander') ) {
+ return;
+ }
+ this.removeData('expander');
+ this.each(function() {
+ var $this = $(this),
+ o = $.meta ? $.extend({}, opts, $this.data()) : opts,
+ details = $this.find('.' + o.detailClass).contents();
+
+ $this.find('.' + o.moreClass).remove();
+ $this.find('.' + o.summaryClass).remove();
+ $this.find('.' + o.detailClass).after(details).remove();
+ $this.find('.' + o.lessClass).remove();
+
+ });
+ }
+ };
+
+ // run the methods (almost always "init")
+ if ( methods[meth] ) {
+ methods[ meth ].call(this);
+ }
+
+ // utility functions
+ function buildHTML(o, blocks) {
+ var el = 'span',
+ summary = o.summary;
+ if ( blocks ) {
+ el = 'div';
+ // if summary ends with a close tag, tuck the moreLabel inside it
+ if ( rLastCloseTag.test(summary) && !o.expandAfterSummary) {
+ summary = summary.replace(rLastCloseTag, o.moreLabel + '$1');
+ } else {
+ // otherwise (e.g. if ends with self-closing tag) just add moreLabel after summary
+ // fixes #19
+ summary += o.moreLabel;
+ }
+
+ // and wrap it in a div
+ summary = '
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index cb2ed1eec19..1b19a383c10 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -292,4 +292,43 @@ class mail_compose_message(osv.osv_memory):
return tools.ustr(result)
return template and EXPRESSION_PATTERN.sub(merge, template)
+
+
+class mail_compose_message_extended(osv.osv_memory):
+ """ Extension of 'mail.compose.message' to support default field values related
+ to CRM-like models that follow the following conventions:
+
+ 1. The model object must have an attribute '_mail_compose_message' equal to True.
+
+ 2. The model should define the following fields:
+ - 'name' as subject of the message (required);
+ - 'email_from' as destination email address (required);
+ - 'email_cc' as cc email addresses (required);
+ - 'section_id.reply_to' as reply-to address (optional).
+ """
+ _inherit = 'mail.compose.message'
+
+ def get_value(self, cr, uid, model, res_id, context=None):
+ """Overrides the default implementation to provide more default field values
+ related to the corresponding CRM case.
+ """
+ result = super(mail_compose_message_extended, self).get_value(cr, uid, model, res_id, context=context)
+ model_obj = self.pool.get(model)
+ if getattr(model_obj, '_mail_compose_message', False) and res_id:
+ data = model_obj.browse(cr, uid , res_id, context)
+ user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
+ result.update({
+ 'model': model,
+ 'res_id': res_id,
+ 'email_from': user.user_email or tools.config.get('email_from', False),
+ 'email_to': data.email_from or False,
+ 'email_cc': tools.ustr(data.email_cc or ''),
+ 'subject': data.name or False,
+ 'body_text': '\n' + tools.ustr(user.signature or ''),
+ 'subtype': 'plain',
+ })
+ if hasattr(data, 'section_id'):
+ result['reply_to'] = data.section_id and data.section_id.reply_to or False
+ return result
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail/wizard/mail_compose_message_view.xml b/addons/mail/wizard/mail_compose_message_view.xml
index 99eb7192738..bcc11c4111d 100644
--- a/addons/mail/wizard/mail_compose_message_view.xml
+++ b/addons/mail/wizard/mail_compose_message_view.xml
@@ -7,23 +7,18 @@
form
diff --git a/addons/marketing_campaign/marketing_campaign.py b/addons/marketing_campaign/marketing_campaign.py
index a6294182301..417bd694624 100644
--- a/addons/marketing_campaign/marketing_campaign.py
+++ b/addons/marketing_campaign/marketing_campaign.py
@@ -439,7 +439,7 @@ class marketing_campaign_activity(osv.osv):
'revenue': fields.float('Revenue', help="Set an expected revenue if you consider that every campaign item that has reached this point has generated a certain revenue. You can get revenue statistics in the Reporting section", digits_compute=dp.get_precision('Sale Price')),
'signal': fields.char('Signal', size=128,
help='An activity with a signal can be called programmatically. Be careful, the workitem is always created when a signal is sent'),
- 'keep_if_condition_not_met': fields.boolean("Don't delete workitems",
+ 'keep_if_condition_not_met': fields.boolean("Don't Delete Workitems",
help="By activating this option, workitems that aren't executed because the condition is not met are marked as cancelled instead of being deleted.")
}
diff --git a/addons/marketing_campaign/marketing_campaign_view.xml b/addons/marketing_campaign/marketing_campaign_view.xml
index 41ed78da709..6a06cb33f1d 100644
--- a/addons/marketing_campaign/marketing_campaign_view.xml
+++ b/addons/marketing_campaign/marketing_campaign_view.xml
@@ -9,6 +9,22 @@
Marketing Campaign
======================
-->
+
+
+
+ marketing.campaign.form
@@ -24,20 +40,30 @@
+
@@ -283,7 +319,7 @@
@@ -297,6 +333,11 @@
+
+
@@ -327,7 +368,7 @@
{"search_default_sales":1}Sales Orders help you manage quotations and orders from your customers. OpenERP suggests that you start by creating a quotation. Once it is confirmed, the quotation will be converted into a Sales Order. OpenERP can handle several types of products so that a sales order may trigger tasks, delivery orders, manufacturing orders, purchases and so on. Based on the configuration of the sales order, a draft invoice will be generated so that you just have to confirm it when you want to bill your customer.
-
+
Sales in Exception
@@ -370,7 +411,7 @@
+ sequence="4"/>
Old Quotations
diff --git a/addons/sale/security/ir.model.access.csv b/addons/sale/security/ir.model.access.csv
index 721d706a5fb..617678eccbe 100644
--- a/addons/sale/security/ir.model.access.csv
+++ b/addons/sale/security/ir.model.access.csv
@@ -57,4 +57,6 @@ access_product_pricelist_type_sale_manager,product.pricelist.type salemanager,pr
access_product_pricelist_sale_manager,product.pricelist salemanager,product.model_product_pricelist,base.group_sale_manager,1,1,1,1
access_product_group_res_partner_sale_manager,res_partner group_sale_manager,base.model_res_partner,base.group_sale_manager,1,1,1,0
access_product_pricelist_version_sale_manager,product.pricelist.version sale_manager,product.model_product_pricelist_version,base.group_sale_manager,1,1,1,1
-access_account_invoice_report_salesman,account.invoice.report salesman,account.model_account_invoice_report,base.group_sale_salesman,1,0,0,0
\ No newline at end of file
+access_account_invoice_report_salesman,account.invoice.report salesman,account.model_account_invoice_report,base.group_sale_salesman,1,0,0,0
+access_stock_warehouse_orderpoint_sale_salesman,stock.warehouse.orderpoint,procurement.model_stock_warehouse_orderpoint,base.group_sale_salesman,1,0,0,0
+access_account_move_line_salesman,account.move.line invoice,account.model_account_move_line,base.group_sale_salesman,1,0,0,0
diff --git a/addons/sale_crm/i18n/ja.po b/addons/sale_crm/i18n/ja.po
index 90dee9e022a..2c6e158a939 100644
--- a/addons/sale_crm/i18n/ja.po
+++ b/addons/sale_crm/i18n/ja.po
@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-02-08 00:37+0000\n"
-"PO-Revision-Date: 2012-06-08 09:02+0000\n"
-"Last-Translator: Tomomi Mengelberg \n"
+"PO-Revision-Date: 2012-07-06 21:31+0000\n"
+"Last-Translator: Akira Hiyama \n"
"Language-Team: Japanese \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-06-09 05:39+0000\n"
-"X-Generator: Launchpad (build 15376)\n"
+"X-Launchpad-Export-Date: 2012-07-07 05:13+0000\n"
+"X-Generator: Launchpad (build 15558)\n"
#. module: sale_crm
#: field:sale.order,categ_id:0
@@ -105,13 +105,13 @@ msgstr "オポチュニティ成立"
#. module: sale_crm
#: view:board.board:0
msgid "My Planned Revenues by Stage"
-msgstr "状況による私の計画売上高"
+msgstr "段階別私の計画売上高"
#. module: sale_crm
#: code:addons/sale_crm/wizard/crm_make_sale.py:110
#, python-format
msgid "Opportunity '%s' is converted to Quotation."
-msgstr "オポチュニティの'%s' は、見積りへ変わりました。"
+msgstr "オポチュニティの'%s' は、見積に変換されました。"
#. module: sale_crm
#: view:sale.order:0
diff --git a/addons/sale_crm/wizard/crm_make_sale_view.xml b/addons/sale_crm/wizard/crm_make_sale_view.xml
index 835e5aa80cc..ef7546107c2 100644
--- a/addons/sale_crm/wizard/crm_make_sale_view.xml
+++ b/addons/sale_crm/wizard/crm_make_sale_view.xml
@@ -9,16 +9,16 @@
form
-
-
- or
-
-
+
diff --git a/addons/sale_mrp/security/ir.model.access.csv b/addons/sale_mrp/security/ir.model.access.csv
index a0f117b61e5..4f0f0f8072c 100644
--- a/addons/sale_mrp/security/ir.model.access.csv
+++ b/addons/sale_mrp/security/ir.model.access.csv
@@ -2,3 +2,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_mrp_bom_user,mrp.bom,mrp.model_mrp_bom,base.group_sale_salesman,1,0,0,0
access_sale_order_manufacturing_user,sale.order manufacturing.user,sale.model_sale_order,mrp.group_mrp_user,1,1,0,0
access_sale_order_line_manufacturing_user,sale.order.line manufacturing.user,sale.model_sale_order_line,mrp.group_mrp_user,1,1,0,0
+access_mrp_bom_revision_salesman,mrp.bom.revision,mrp.model_mrp_bom_revision,base.group_sale_salesman,1,0,0,0
diff --git a/addons/share/static/src/css/share.css b/addons/share/static/src/css/share.css
index 997c070fe54..dbbb8bea943 100644
--- a/addons/share/static/src/css/share.css
+++ b/addons/share/static/src/css/share.css
@@ -1,7 +1,4 @@
-button.oe_share_mail {
- display: none;
-}
-
-a.oe_share_link, a.oe_share {
+/* Added invite button, hidden by default */
+button.oe_share_invite {
display: none;
}
diff --git a/addons/share/static/src/js/share.js b/addons/share/static/src/js/share.js
index e88616546a3..33aa3d1aab9 100644
--- a/addons/share/static/src/js/share.js
+++ b/addons/share/static/src/js/share.js
@@ -50,29 +50,46 @@ openerp.share = function(session) {
session.connection.share_flag.done(yes).fail(no);
}
+ /* Extend the Sidebar to add Share and Embed links in the 'More' menu */
session.web.Sidebar = session.web.Sidebar.extend({
- add_default_sections: function() {
- this._super();
+
+ start: function() {
var self = this;
+ this._super(this);
has_share(function() {
- self.add_items('other', [{
- label: 'Share',
- callback: self.on_sidebar_click_share,
- classname: 'oe_share',
- }]);
+ self.add_items('other', [
+ { label: 'Share',
+ callback: self.on_click_share,
+ classname: 'oe_share' },
+ { label: 'Embed',
+ callback: self.on_click_share_link,
+ classname: 'oe_share' },
+ ]);
});
},
- on_sidebar_click_share: function(item) {
+
+ on_click_share: function(item) {
var view = this.getParent()
- launch_wizard(this, view);
+ launch_wizard(this, view, 'emails', false);
+ },
+
+ on_click_share_link: function(item) {
+ var view = this.getParent()
+ launch_wizard(this, view, 'embedded', false);
},
});
+ /**
+ * Extends mail (Chatter widget)
+ * - show the 'invite' button' only we came on the form view through
+ * an action. We do this because 'invite' is based on the share
+ * mechanism, and it tries to share an action.
+ */
session.mail.RecordThread.include( {
start: function() {
start_res = this._super.apply(this, arguments);
if (has_action_id) {
- this.$element.find('button.oe_share_mail').show();
+ this.$element.find('button.oe_share_invite').show();
}
return start_res;
}
@@ -83,12 +100,7 @@ openerp.share = function(session) {
var self = this;
this.check_if_action_is_defined();
has_share(function() {
- self.$element.find('a.oe_share_link').click(self.on_click_share_link);
- self.$element.find('a.oe_share').click(self.on_click_share);
- self.$element.delegate('button.oe_share_mail', 'click', self.on_click_share_mail);
- }, function() {
- self.$element.find('a.oe_share_link').remove();
- self.$element.find('a.oe_share').remove();
+ self.$element.delegate('button.oe_share_invite', 'click', self.on_click_share_invite);
});
return this._super.apply(this, arguments);
},
@@ -96,23 +108,13 @@ openerp.share = function(session) {
check_if_action_is_defined: function() {
if (this.action && this.action.id) {
has_action_id = true;
- this.$element.find('a.oe_share_link').show();
- this.$element.find('a.oe_share').show();
}
else {
has_action_id = false;
}
},
-
- on_click_share_link: function(e) {
- e.preventDefault();
- launch_wizard(this, this.views[this.active_view].controller, 'embedded', false);
- },
- on_click_share: function(e) {
- e.preventDefault();
- launch_wizard(this, this.views[this.active_view].controller, 'emails', false);
- },
- on_click_share_mail: function(e) {
+
+ on_click_share_invite: function(e) {
e.preventDefault();
launch_wizard(this, this.views[this.active_view].controller, 'emails', true);
},
diff --git a/addons/share/static/src/xml/share.xml b/addons/share/static/src/xml/share.xml
index e51dc135c0b..1d9bc987afc 100644
--- a/addons/share/static/src/xml/share.xml
+++ b/addons/share/static/src/xml/share.xml
@@ -3,18 +3,11 @@
-->
-
-
-
-
-
-
-
-
+
+
-
+
-
diff --git a/addons/share/wizard/share_wizard.py b/addons/share/wizard/share_wizard.py
index 55d43453775..41871480f45 100644
--- a/addons/share/wizard/share_wizard.py
+++ b/addons/share/wizard/share_wizard.py
@@ -48,7 +48,7 @@ RANDOM_PASS_CHARACTERS = 'aaaabcdeeeefghjkmnpqrstuvwxyzAAAABCDEEEEFGHJKLMNPQRSTU
def generate_random_pass():
return ''.join(random.sample(RANDOM_PASS_CHARACTERS,10))
-class share_wizard(osv.osv_memory):
+class share_wizard(osv.TransientModel):
_name = 'share.wizard'
_description = 'Share Wizard'
@@ -177,9 +177,10 @@ class share_wizard(osv.osv_memory):
'name': fields.char('Share Title', size=64, required=True, help="Title for the share (displayed to users as menu and shortcut name)"),
'record_name': fields.char('Record name', size=128, help="Name of the shared record, if sharing a precise record"),
'message': fields.text("Personal Message", help="An optional personal message, to be included in the email notification."),
-
- 'embed_code': fields.function(_embed_code, type='text'),
- 'embed_option_title': fields.boolean("Display title"),
+ 'embed_code': fields.function(_embed_code, type='text', string='Code',
+ help="Embed this code in your documents to provide a link to the "\
+ "shared document."),
+ 'embed_option_title': fields.boolean('Display title'),
'embed_option_search': fields.boolean('Display search view'),
'embed_url': fields.function(_embed_url, string='Share URL', type='char', size=512, readonly=True),
}
@@ -903,8 +904,11 @@ class share_result_line(osv.osv_memory):
def _share_url(self, cr, uid, ids, _fieldname, _args, context=None):
result = dict.fromkeys(ids, '')
for this in self.browse(cr, uid, ids, context=context):
- data = dict(dbname=cr.dbname, login=this.login, password='')
- result[this.id] = this.share_wizard_id.share_url_template() % data
+ data = dict(dbname=cr.dbname, login=this.login, password=this.password)
+ if this.share_wizard_id and this.share_wizard_id.action_id:
+ data['action_id'] = this.share_wizard_id.action_id.id
+ ctx = dict(context, share_url_template_hash_arguments=['action_id'])
+ result[this.id] = this.share_wizard_id.share_url_template(context=ctx) % data
return result
_columns = {
diff --git a/addons/share/wizard/share_wizard_view.xml b/addons/share/wizard/share_wizard_view.xml
index ee5d4dd23b9..ad4df1a5193 100644
--- a/addons/share/wizard/share_wizard_view.xml
+++ b/addons/share/wizard/share_wizard_view.xml
@@ -8,11 +8,6 @@
form
-
-
- or
-
-
@@ -21,6 +16,11 @@
string="Optionally, you may specify an additional domain restriction that will be applied to the shared data."/>
+
@@ -1612,13 +1609,6 @@
res_model="stock.move"
src_model="product.product"/>
-
-
Quantity has been changed to %s %s for %s location.") % (data.new_quantity,uom.name,location_name)
- prod_obj.message_append_note(cr, uid, [prod.id], body=message, context=context)
+ location_name = location_obj.browse(cr, uid, data.location_id.id, context=context).name
+ message = _("Quantity has been changed to %s %s for %s location.") % (data.new_quantity, data.product_id.uom_id.name, location_name)
+ prod_obj.message_append_note(cr, uid, [data.product_id.id], body=message, context=context)
stock_change_product_qty()
diff --git a/addons/stock/wizard/stock_change_product_qty_view.xml b/addons/stock/wizard/stock_change_product_qty_view.xml
index dc00fdbe736..e360f5aa025 100644
--- a/addons/stock/wizard/stock_change_product_qty_view.xml
+++ b/addons/stock/wizard/stock_change_product_qty_view.xml
@@ -7,17 +7,17 @@
form
-
-
- or
-
-
+
diff --git a/addons/stock/wizard/stock_change_standard_price_view.xml b/addons/stock/wizard/stock_change_standard_price_view.xml
index 968a268a5ef..6062c946d07 100644
--- a/addons/stock/wizard/stock_change_standard_price_view.xml
+++ b/addons/stock/wizard/stock_change_standard_price_view.xml
@@ -7,15 +7,15 @@
form
-
-
- or
-
-
+
diff --git a/addons/stock/wizard/stock_fill_inventory_view.xml b/addons/stock/wizard/stock_fill_inventory_view.xml
index ea07955eff2..75a7b13233b 100644
--- a/addons/stock/wizard/stock_fill_inventory_view.xml
+++ b/addons/stock/wizard/stock_fill_inventory_view.xml
@@ -7,17 +7,17 @@
form
-
-
- or
-
-
+
diff --git a/addons/stock/wizard/stock_inventory_line_split_view.xml b/addons/stock/wizard/stock_inventory_line_split_view.xml
index d8a808ed5db..5072007f210 100644
--- a/addons/stock/wizard/stock_inventory_line_split_view.xml
+++ b/addons/stock/wizard/stock_inventory_line_split_view.xml
@@ -7,11 +7,6 @@
form
-
-
- or
-
-
@@ -45,6 +40,11 @@
+
diff --git a/addons/stock/wizard/stock_inventory_merge_view.xml b/addons/stock/wizard/stock_inventory_merge_view.xml
index 0dcca2de211..0386e429ee6 100644
--- a/addons/stock/wizard/stock_inventory_merge_view.xml
+++ b/addons/stock/wizard/stock_inventory_merge_view.xml
@@ -8,13 +8,13 @@
form
-
+
+
+
-
-
+
diff --git a/addons/stock/wizard/stock_invoice_onshipping.py b/addons/stock/wizard/stock_invoice_onshipping.py
index 46c55311045..ca294f8ec79 100644
--- a/addons/stock/wizard/stock_invoice_onshipping.py
+++ b/addons/stock/wizard/stock_invoice_onshipping.py
@@ -36,7 +36,7 @@ class stock_invoice_onshipping(osv.osv_memory):
context = {}
model = context.get('active_model')
- if not model or model != 'stock.picking':
+ if not model or 'stock.picking' not in model:
return []
model_pool = self.pool.get(model)
diff --git a/addons/stock/wizard/stock_invoice_onshipping_view.xml b/addons/stock/wizard/stock_invoice_onshipping_view.xml
index 088498292ae..20f05f394fd 100644
--- a/addons/stock/wizard/stock_invoice_onshipping_view.xml
+++ b/addons/stock/wizard/stock_invoice_onshipping_view.xml
@@ -7,16 +7,16 @@
form
-
-
- or
-
-
+
diff --git a/addons/stock/wizard/stock_location_product_view.xml b/addons/stock/wizard/stock_location_product_view.xml
index b1f77576392..f0a52933c8a 100644
--- a/addons/stock/wizard/stock_location_product_view.xml
+++ b/addons/stock/wizard/stock_location_product_view.xml
@@ -7,17 +7,17 @@
form
-
-
- or
-
-
+
diff --git a/addons/stock/wizard/stock_move_view.xml b/addons/stock/wizard/stock_move_view.xml
index 9655edf49b8..5ecfc9a85a1 100644
--- a/addons/stock/wizard/stock_move_view.xml
+++ b/addons/stock/wizard/stock_move_view.xml
@@ -9,11 +9,6 @@
form
-
-
- or
-
-
@@ -23,6 +18,11 @@
+
@@ -42,11 +42,6 @@
form
-
-
- or
-
-
@@ -57,6 +52,11 @@
+
@@ -76,9 +76,6 @@
form
-
-
-
@@ -113,6 +110,9 @@
+
diff --git a/addons/stock/wizard/stock_partial_move_view.xml b/addons/stock/wizard/stock_partial_move_view.xml
index 497467025b5..3e0699ec3d8 100644
--- a/addons/stock/wizard/stock_partial_move_view.xml
+++ b/addons/stock/wizard/stock_partial_move_view.xml
@@ -21,13 +21,13 @@
form
-
+
+
+
-
-
+
diff --git a/addons/stock/wizard/stock_partial_picking_view.xml b/addons/stock/wizard/stock_partial_picking_view.xml
index c8da4459efa..fdbcabb9ed7 100644
--- a/addons/stock/wizard/stock_partial_picking_view.xml
+++ b/addons/stock/wizard/stock_partial_picking_view.xml
@@ -16,11 +16,6 @@
form
-
-
- or
-
-
@@ -36,6 +31,11 @@
+
diff --git a/addons/stock/wizard/stock_return_picking_view.xml b/addons/stock/wizard/stock_return_picking_view.xml
index 06e318c295e..5cdad44f681 100644
--- a/addons/stock/wizard/stock_return_picking_view.xml
+++ b/addons/stock/wizard/stock_return_picking_view.xml
@@ -59,16 +59,16 @@
form
-
-
- or
-
-
+
diff --git a/addons/stock/wizard/stock_splitinto_view.xml b/addons/stock/wizard/stock_splitinto_view.xml
index 573014b7cac..52b182a3f27 100644
--- a/addons/stock/wizard/stock_splitinto_view.xml
+++ b/addons/stock/wizard/stock_splitinto_view.xml
@@ -7,15 +7,15 @@
form
-
-
- or
-
-
+
diff --git a/addons/stock_planning/i18n/ja.po b/addons/stock_planning/i18n/ja.po
index 0cc365acbe0..4e21f56fa79 100644
--- a/addons/stock_planning/i18n/ja.po
+++ b/addons/stock_planning/i18n/ja.po
@@ -8,21 +8,21 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-02-08 00:37+0000\n"
-"PO-Revision-Date: 2012-06-30 06:17+0000\n"
+"PO-Revision-Date: 2012-07-04 23:38+0000\n"
"Last-Translator: Akira Hiyama \n"
"Language-Team: Japanese \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-07-01 04:40+0000\n"
-"X-Generator: Launchpad (build 15520)\n"
+"X-Launchpad-Export-Date: 2012-07-06 04:58+0000\n"
+"X-Generator: Launchpad (build 15558)\n"
#. module: stock_planning
#: code:addons/stock_planning/wizard/stock_planning_createlines.py:73
#, python-format
msgid ""
"No forecasts for selected period or no products in selected category !"
-msgstr ""
+msgstr "選択した期間の予測がないか、選択された分類の中に製品がありません。"
#. module: stock_planning
#: help:stock.planning,stock_only:0
@@ -30,76 +30,76 @@ msgid ""
"Check to calculate stock location of selected warehouse only. If not "
"selected calculation is made for input, stock and output location of "
"warehouse."
-msgstr ""
+msgstr "選択された倉庫のみの在庫場所を計算するためにチェックします。選択しない場合の計算は倉庫の入力、在庫、出力場所によってなされます。"
#. module: stock_planning
#: field:stock.planning,maximum_op:0
msgid "Maximum Rule"
-msgstr ""
+msgstr "最大値のルール"
#. module: stock_planning
#: view:stock.planning:0
#: view:stock.sale.forecast:0
msgid "Group By..."
-msgstr ""
+msgstr "グループ化…"
#. module: stock_planning
#: help:stock.sale.forecast,product_amt:0
msgid ""
"Forecast value which will be converted to Product Quantity according to "
"prices."
-msgstr ""
+msgstr "予測値は価格により製品数量に変換されます。"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:626
#: code:addons/stock_planning/stock_planning.py:670
#, python-format
msgid "Incoming Left must be greater than 0 !"
-msgstr ""
+msgstr "入荷の残りは0より大きい必要があります。"
#. module: stock_planning
#: help:stock.planning,outgoing_before:0
msgid ""
"Planned Out in periods before calculated. Between start date of current "
"period and one day before start of calculated period."
-msgstr ""
+msgstr "計算される前に期間内で計画された出荷です。現在の期間の開始日と計算された期間の開始1日前の間です。"
#. module: stock_planning
#: help:stock.sale.forecast.createlines,warehouse_id:0
msgid ""
"Warehouse which forecasts will concern. If during stock planning you will "
"need sales forecast for all warehouses choose any warehouse now."
-msgstr ""
+msgstr "予測値が関係する倉庫です。在庫計画の期間に全ての倉庫の受注予測を必要とするなら、今、倉庫を選択して下さい。"
#. module: stock_planning
#: field:stock.planning,outgoing_left:0
msgid "Expected Out"
-msgstr ""
+msgstr "期待された出荷"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid " "
-msgstr ""
+msgstr " "
#. module: stock_planning
#: field:stock.planning,incoming_left:0
msgid "Incoming Left"
-msgstr ""
+msgstr "入荷残り"
#. module: stock_planning
#: view:stock.sale.forecast.createlines:0
msgid "Create Forecasts Lines"
-msgstr ""
+msgstr "予測行の作成"
#. module: stock_planning
#: help:stock.planning,outgoing:0
msgid "Quantity of all confirmed outgoing moves in calculated Period."
-msgstr ""
+msgstr "計算された期間の全ての確認された出荷移動の数量"
#. module: stock_planning
#: view:stock.period.createlines:0
msgid "Create Daily Periods"
-msgstr ""
+msgstr "1日の期間の作成"
#. module: stock_planning
#: view:stock.planning:0
@@ -109,45 +109,45 @@ msgstr ""
#: field:stock.sale.forecast,company_id:0
#: field:stock.sale.forecast.createlines,company_id:0
msgid "Company"
-msgstr ""
+msgstr "会社"
#. module: stock_planning
#: help:stock.planning,warehouse_forecast:0
msgid ""
"All sales forecasts for selected Warehouse of selected Product during "
"selected Period."
-msgstr ""
+msgstr "選択した期間中に選択した製品の選択した倉庫のための全ての受注予測です。"
#. module: stock_planning
#: view:stock.planning:0
msgid "Minimum Stock Rule Indicators"
-msgstr ""
+msgstr "最小在庫ルールの指標"
#. module: stock_planning
#: help:stock.sale.forecast.createlines,period_id:0
msgid "Period which forecasts will concern."
-msgstr ""
+msgstr "予測が関係する期間"
#. module: stock_planning
#: field:stock.planning,stock_only:0
msgid "Stock Location Only"
-msgstr ""
+msgstr "在庫場所のみ"
#. module: stock_planning
#: help:stock.planning,already_out:0
msgid ""
"Quantity which is already dispatched out of this warehouse in current period."
-msgstr ""
+msgstr "現在の期間でこの倉庫の既に割り当てられた数量"
#. module: stock_planning
#: field:stock.planning,incoming:0
msgid "Confirmed In"
-msgstr ""
+msgstr "入庫確認"
#. module: stock_planning
#: view:stock.planning:0
msgid "Current Period Situation"
-msgstr ""
+msgstr "現在期間の状況"
#. module: stock_planning
#: model:ir.actions.act_window,help:stock_planning.action_stock_period_createlines_form
@@ -156,11 +156,13 @@ msgid ""
"are independent of financial periods. If you need periods other than day-, "
"week- or month-based, you may also add then manually."
msgstr ""
+"このウィザードは在庫計画の期間の作成を手助けします。こららの期間は会計上の期間とは独立しています。日、週、月ベースの他の期間を必要とする場合は、手動で追加"
+"することができます。"
#. module: stock_planning
#: view:stock.period.createlines:0
msgid "Create Monthly Periods"
-msgstr ""
+msgstr "月次期間の作成"
#. module: stock_planning
#: model:ir.model,name:stock_planning.model_stock_period_createlines
@@ -170,46 +172,46 @@ msgstr ""
#. module: stock_planning
#: field:stock.planning,outgoing_before:0
msgid "Planned Out Before"
-msgstr ""
+msgstr "先行計画出荷"
#. module: stock_planning
#: field:stock.planning.createlines,forecasted_products:0
msgid "All Products with Forecast"
-msgstr ""
+msgstr "予想を持つ全製品"
#. module: stock_planning
#: help:stock.planning,maximum_op:0
msgid "Maximum quantity set in Minimum Stock Rules for this Warehouse"
-msgstr ""
+msgstr "この倉庫のため、最大数量が最小在庫ルールで設定されます。"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Periods :"
-msgstr ""
+msgstr "期間:"
#. module: stock_planning
#: help:stock.planning,procure_to_stock:0
msgid ""
"Check to make procurement to stock location of selected warehouse. If not "
"selected procurement will be made into input location of warehouse."
-msgstr ""
+msgstr "選択された倉庫の在庫場所で調達を行うためにチェックします。選択しない場合は、倉庫の入力場所の中で調達が行われます。"
#. module: stock_planning
#: help:stock.planning,already_in:0
msgid ""
"Quantity which is already picked up to this warehouse in current period."
-msgstr ""
+msgstr "現在の期間に既にこの倉庫に集められた数量"
#. module: stock_planning
#: code:addons/stock_planning/wizard/stock_planning_forecast.py:60
#, python-format
msgid "No products in selected category !"
-msgstr ""
+msgstr "選択された分類の中に製品がありません。"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Stock and Sales Forecast"
-msgstr ""
+msgstr "在庫と受注予測"
#. module: stock_planning
#: model:ir.model,name:stock_planning.model_stock_sale_forecast
@@ -219,12 +221,12 @@ msgstr ""
#. module: stock_planning
#: field:stock.planning,to_procure:0
msgid "Planned In"
-msgstr ""
+msgstr "計画入庫"
#. module: stock_planning
#: field:stock.planning,stock_simulation:0
msgid "Stock Simulation"
-msgstr ""
+msgstr "在庫シミュレーション"
#. module: stock_planning
#: model:ir.model,name:stock_planning.model_stock_planning_createlines
@@ -237,60 +239,60 @@ msgid ""
"Confirmed incoming in periods before calculated (Including Already In). "
"Between start date of current period and one day before start of calculated "
"period."
-msgstr ""
+msgstr "計算する前に期間内で確認された入庫(既に入庫分を含む)です。現在の期間の開始日と計算された期間の開始1日前の間です。"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Search Sales Forecast"
-msgstr ""
+msgstr "受注予測の検索"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period5_per_user:0
msgid "This User Period5"
-msgstr ""
+msgstr "このユーザの期間5"
#. module: stock_planning
#: help:stock.planning,history:0
msgid "History of procurement or internal supply of this planning line."
-msgstr ""
+msgstr "この計画行の調達、または内部供給の履歴"
#. module: stock_planning
#: help:stock.planning,company_forecast:0
msgid ""
"All sales forecasts for whole company (for all Warehouses) of selected "
"Product during selected Period."
-msgstr ""
+msgstr "選択した期間中に選択した製品の会社全体(全ての倉庫)ための全ての受注予測です。"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period1_per_user:0
msgid "This User Period1"
-msgstr ""
+msgstr "このユーザの期間1"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period3_per_user:0
msgid "This User Period3"
-msgstr ""
+msgstr "このユーザの期間3"
#. module: stock_planning
#: view:stock.planning:0
msgid "Stock Planning"
-msgstr ""
+msgstr "在庫計画"
#. module: stock_planning
#: field:stock.planning,minimum_op:0
msgid "Minimum Rule"
-msgstr ""
+msgstr "最小値のルール"
#. module: stock_planning
#: view:stock.planning:0
msgid "Procure Incoming Left"
-msgstr ""
+msgstr "調達入庫の残り"
#. module: stock_planning
#: view:stock.planning.createlines:0
#: view:stock.sale.forecast.createlines:0
msgid "Create"
-msgstr ""
+msgstr "作成"
#. module: stock_planning
#: model:ir.actions.act_window,name:stock_planning.action_view_stock_planning_form
@@ -298,12 +300,12 @@ msgstr ""
#: model:ir.ui.menu,name:stock_planning.menu_stock_planning_manual
#: view:stock.planning:0
msgid "Master Procurement Schedule"
-msgstr ""
+msgstr "マスター調達スケジュール"
#. module: stock_planning
#: field:stock.planning,line_time:0
msgid "Past/Future"
-msgstr ""
+msgstr "過去 / 将来"
#. module: stock_planning
#: view:stock.period:0
@@ -311,17 +313,17 @@ msgstr ""
#: field:stock.planning,state:0
#: field:stock.sale.forecast,state:0
msgid "State"
-msgstr ""
+msgstr "状態"
#. module: stock_planning
#: help:stock.sale.forecast.createlines,product_categ_id:0
msgid "Product Category of products which created forecasts will concern."
-msgstr ""
+msgstr "作成された予測が関係するであろう製品の製品分類です。"
#. module: stock_planning
#: model:ir.model,name:stock_planning.model_stock_period
msgid "stock period"
-msgstr ""
+msgstr "在庫期間"
#. module: stock_planning
#: model:ir.model,name:stock_planning.model_stock_sale_forecast_createlines
@@ -334,7 +336,7 @@ msgstr ""
#: field:stock.sale.forecast,warehouse_id:0
#: field:stock.sale.forecast.createlines,warehouse_id:0
msgid "Warehouse"
-msgstr ""
+msgstr "倉庫"
#. module: stock_planning
#: help:stock.planning,stock_simulation:0
@@ -346,21 +348,26 @@ msgid ""
"Initial Stock - Planned Out Before + Incoming Before - Planned Out + Planned "
"In."
msgstr ""
+"選択された期間終了時の在庫シミュレーション\n"
+" 現在の期間のため:\n"
+"初期在庫 - 既出庫 + 既入庫 - 期待出庫 + 入庫残\n"
+" その先の期間のため:\n"
+"初期在庫 - 先行計画出庫 + 先行入庫 - 計画出庫 + 計画入庫"
#. module: stock_planning
#: help:stock.sale.forecast,analyze_company:0
msgid "Check this box to see the sales for whole company."
-msgstr ""
+msgstr "会社の全体のための受注を見るためにこのボックスをチェックして下さい。"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Per Department :"
-msgstr ""
+msgstr "部署毎:"
#. module: stock_planning
#: field:stock.planning,incoming_before:0
msgid "Incoming Before"
-msgstr ""
+msgstr "先行入庫"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:641
@@ -382,6 +389,17 @@ msgid ""
" \n"
" Stock Simulation: %s Minimum stock: %s"
msgstr ""
+" MPSによりユーザのために作成された調達:%s 作成日:%s \n"
+" 期間:%s \n"
+" 状態に応じて: \n"
+" 倉庫予測:%s \n"
+" 初期在庫:%s \n"
+" 計画出庫:%s 計画入庫:%s \n"
+" 既出庫:%s 既入庫:%s \n"
+" 確認済出庫:%s 確認済入庫:%s \n"
+" 先行計画出庫:%s 先行確認済入庫:%s \n"
+" 期待出庫:%s 入庫残:%s \n"
+" 在庫シミュレーション:%s 最小在庫:%s"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:626
@@ -392,55 +410,55 @@ msgstr ""
#: code:addons/stock_planning/wizard/stock_planning_forecast.py:60
#, python-format
msgid "Error !"
-msgstr ""
+msgstr "エラー"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_user_id:0
msgid "This User"
-msgstr ""
+msgstr "このユーザ"
#. module: stock_planning
#: view:stock.planning:0
msgid "Forecasts"
-msgstr ""
+msgstr "予測"
#. module: stock_planning
#: view:stock.planning:0
msgid "Supply from Another Warehouse"
-msgstr ""
+msgstr "他の倉庫からの供給"
#. module: stock_planning
#: view:stock.planning:0
msgid "Calculate Planning"
-msgstr ""
+msgstr "計画の計算"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:146
#, python-format
msgid "Invalid action !"
-msgstr ""
+msgstr "無効なアクションです。"
#. module: stock_planning
#: help:stock.planning,stock_start:0
msgid "Stock quantity one day before current period."
-msgstr ""
+msgstr "現在の期間前の1日の在庫数量"
#. module: stock_planning
#: view:stock.planning:0
msgid "Procurement history"
-msgstr ""
+msgstr "調達履歴"
#. module: stock_planning
#: help:stock.planning,product_uom:0
msgid ""
"Unit of Measure used to show the quantities of stock calculation.You can use "
"units from default category or from second category (UoS category)."
-msgstr ""
+msgstr "在庫計算の数量を表示するため使用する単位。デフォルト分類から、または第2分類(販売単位分類)から単位を使うことができます。"
#. module: stock_planning
#: view:stock.period.createlines:0
msgid "Create Weekly Periods"
-msgstr ""
+msgstr "週毎の期間を作成"
#. module: stock_planning
#: model:ir.actions.act_window,help:stock_planning.action_stock_period_form
@@ -449,56 +467,57 @@ msgid ""
"account periods. You can use wizard for creating periods and review them "
"here."
msgstr ""
+"在庫期間は在庫計画のために使用されます。在庫期間はアカウント期間から独立しています。ここからウィザードを使用して期間の作成やレビューができます。"
#. module: stock_planning
#: view:stock.planning:0
msgid "Calculated Period Simulation"
-msgstr ""
+msgstr "計算済期間シミュレーション"
#. module: stock_planning
#: view:stock.period.createlines:0
msgid "Cancel"
-msgstr ""
+msgstr "キャンセル"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period4_per_user:0
msgid "This User Period4"
-msgstr ""
+msgstr "このユーザの期間4"
#. module: stock_planning
#: view:stock.period:0
msgid "Stock and Sales Period"
-msgstr ""
+msgstr "在庫と受注の期間"
#. module: stock_planning
#: field:stock.planning,company_forecast:0
msgid "Company Forecast"
-msgstr ""
+msgstr "会社の予測"
#. module: stock_planning
#: help:stock.planning,minimum_op:0
msgid "Minimum quantity set in Minimum Stock Rules for this Warehouse"
-msgstr ""
+msgstr "最小数量はこの倉庫のために最小在庫ルールで設定します。"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Per User :"
-msgstr ""
+msgstr "ユーザ毎:"
#. module: stock_planning
#: help:stock.planning.createlines,warehouse_id:0
msgid "Warehouse which planning will concern."
-msgstr ""
+msgstr "計画が関連する倉庫"
#. module: stock_planning
#: field:stock.sale.forecast,user_id:0
msgid "Created/Validated by"
-msgstr ""
+msgstr "作成者 / 検証者"
#. module: stock_planning
#: field:stock.planning,warehouse_forecast:0
msgid "Warehouse Forecast"
-msgstr ""
+msgstr "倉庫予測"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:674
@@ -506,106 +525,106 @@ msgstr ""
msgid ""
"You must specify a Source Warehouse different than calculated (destination) "
"Warehouse !"
-msgstr ""
+msgstr "計算された(到着先)倉庫と異なる、元の倉庫を指定する必要があります。"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:146
#, python-format
msgid "Cannot delete a validated sales forecast!"
-msgstr ""
+msgstr "検証済受注予測は削除できません。"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period5_per_company:0
msgid "This Company Period5"
-msgstr ""
+msgstr "この会社の期間5"
#. module: stock_planning
#: field:stock.sale.forecast,product_uom:0
msgid "Product UoM"
-msgstr ""
+msgstr "製品単位"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period1_per_company:0
msgid "This Company Period1"
-msgstr ""
+msgstr "この会社の期間1"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period2_per_company:0
msgid "This Company Period2"
-msgstr ""
+msgstr "この会社の期間2"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period3_per_company:0
msgid "This Company Period3"
-msgstr ""
+msgstr "この会社の期間3"
#. module: stock_planning
#: field:stock.period,date_start:0
#: field:stock.period.createlines,date_start:0
msgid "Start Date"
-msgstr ""
+msgstr "開始日"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period2_per_user:0
msgid "This User Period2"
-msgstr ""
+msgstr "このユーザの期間2"
#. module: stock_planning
#: field:stock.planning,confirmed_forecasts_only:0
msgid "Validated Forecasts"
-msgstr ""
+msgstr "検証済予測"
#. module: stock_planning
#: help:stock.planning.createlines,product_categ_id:0
msgid ""
"Planning will be created for products from Product Category selected by this "
"field. This field is ignored when you check \"All Forecasted Product\" box."
-msgstr ""
+msgstr "計画はこの項目により選択した製品分類の製品のために作成されます。全ての製品予測をチェックした場合、この項目は無視されます。"
#. module: stock_planning
#: field:stock.planning,planned_outgoing:0
msgid "Planned Out"
-msgstr ""
+msgstr "計画出庫"
#. module: stock_planning
#: field:stock.sale.forecast,product_qty:0
msgid "Forecast Quantity"
-msgstr ""
+msgstr "予測数量"
#. module: stock_planning
#: view:stock.planning:0
msgid "Forecast"
-msgstr ""
+msgstr "予測"
#. module: stock_planning
#: selection:stock.period,state:0
#: selection:stock.planning,state:0
#: selection:stock.sale.forecast,state:0
msgid "Draft"
-msgstr ""
+msgstr "ドラフト"
#. module: stock_planning
#: view:stock.period:0
msgid "Closed"
-msgstr ""
+msgstr "閉じた"
#. module: stock_planning
#: view:stock.planning:0
#: view:stock.sale.forecast:0
msgid "Warehouse "
-msgstr ""
+msgstr "倉庫 "
#. module: stock_planning
#: help:stock.sale.forecast,product_uom:0
msgid ""
"Unit of Measure used to show the quantities of stock calculation.You can use "
"units form default category or from second category (UoS category)."
-msgstr ""
+msgstr "在庫計算の数量を示すために使用される単位。デフォルト分類から、または第2分類(販売単位分類)から単位を使用することができます。"
#. module: stock_planning
#: view:stock.planning:0
msgid "Planning and Situation for Calculated Period"
-msgstr ""
+msgstr "計算された期間のための計画と状況"
#. module: stock_planning
#: help:stock.planning,planned_outgoing:0
@@ -614,54 +633,56 @@ msgid ""
"Period of selected Product. To plan this value look at Confirmed Out or "
"Sales Forecasts. This value should be equal or greater than Confirmed Out."
msgstr ""
+"選択した製品の選択した期間中の選択した倉庫からの計画出荷数量を入力します。出荷確認や受注予測ではこの値を見て計画します。この値は確認出荷以上である必要があ"
+"ります。"
#. module: stock_planning
#: view:stock.period:0
msgid "Current Periods"
-msgstr ""
+msgstr "現在期間"
#. module: stock_planning
#: view:stock.planning:0
msgid "Internal Supply"
-msgstr ""
+msgstr "内部供給"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:724
#, python-format
msgid "%s Pick List %s (%s, %s) %s %s \n"
-msgstr ""
+msgstr "%s 集荷リスト %s (%s, %s) %s %s \n"
#. module: stock_planning
#: model:ir.actions.act_window,name:stock_planning.action_stock_sale_forecast_createlines_form
#: model:ir.ui.menu,name:stock_planning.menu_stock_sale_forecast_createlines
msgid "Create Sales Forecasts"
-msgstr ""
+msgstr "受注予測の作成"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period4_id:0
msgid "Period4"
-msgstr ""
+msgstr "期間4"
#. module: stock_planning
#: field:stock.period,name:0
#: field:stock.period.createlines,name:0
msgid "Period Name"
-msgstr ""
+msgstr "期間名"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period2_id:0
msgid "Period2"
-msgstr ""
+msgstr "期間2"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period3_id:0
msgid "Period3"
-msgstr ""
+msgstr "期間3"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period1_id:0
msgid "Period1"
-msgstr ""
+msgstr "期間1"
#. module: stock_planning
#: model:ir.actions.act_window,help:stock_planning.action_stock_planning_createlines_form
@@ -670,65 +691,67 @@ msgid ""
"warehouse, so you don't have to create them one by one. The wizard doesn't "
"duplicate lines if they already exist for this selection."
msgstr ""
+"このウィザードは所定の選択された期間と倉庫のためにMPS計画行の作成を手助けします。そしてひとつひとつそれを作る必要はありません。それらがこの選択のために"
+"既に存在するなら、ウィザードは重複する行を作成しません。"
#. module: stock_planning
#: field:stock.planning,outgoing:0
msgid "Confirmed Out"
-msgstr ""
+msgstr "確認済出庫"
#. module: stock_planning
#: model:ir.actions.act_window,name:stock_planning.action_stock_planning_createlines_form
#: model:ir.ui.menu,name:stock_planning.menu_stock_planning_createlines
#: view:stock.planning.createlines:0
msgid "Create Stock Planning Lines"
-msgstr ""
+msgstr "在庫計画行の作成"
#. module: stock_planning
#: view:stock.planning:0
msgid "General Info"
-msgstr ""
+msgstr "一般情報"
#. module: stock_planning
#: model:ir.actions.act_window,name:stock_planning.action_view_stock_sale_forecast_form
msgid "Sales Forecast"
-msgstr ""
+msgstr "受注予測"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period1_per_warehouse:0
msgid "This Warehouse Period1"
-msgstr ""
+msgstr "この倉庫の期間1"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Sales History"
-msgstr ""
+msgstr "受注履歴"
#. module: stock_planning
#: field:stock.planning,supply_warehouse_id:0
msgid "Source Warehouse"
-msgstr ""
+msgstr "元の倉庫"
#. module: stock_planning
#: help:stock.sale.forecast,product_qty:0
msgid "Forecast Product quantity."
-msgstr ""
+msgstr "製品数量の予測"
#. module: stock_planning
#: field:stock.planning,stock_supply_location:0
msgid "Stock Supply Location"
-msgstr ""
+msgstr "在庫供給場所"
#. module: stock_planning
#: help:stock.period.createlines,date_stop:0
msgid "Ending date for planning period."
-msgstr ""
+msgstr "計画期間の終了日"
#. module: stock_planning
#: help:stock.planning.createlines,forecasted_products:0
msgid ""
"Check this box to create planning for all products having any forecast for "
"selected Warehouse and Period. Product Category field will be ignored."
-msgstr ""
+msgstr "選択した倉庫と期間の全ての製品が任意の予測を持つための計画を作成するにはこのボックスをチェックします。製品分類項目は無視されます。"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:632
@@ -736,19 +759,19 @@ msgstr ""
#: code:addons/stock_planning/stock_planning.py:702
#, python-format
msgid "MPS(%s) %s"
-msgstr ""
+msgstr "MPS(%s)%s"
#. module: stock_planning
#: field:stock.planning,already_in:0
msgid "Already In"
-msgstr ""
+msgstr "既入庫"
#. module: stock_planning
#: field:stock.planning,product_uom_categ:0
#: field:stock.planning,product_uos_categ:0
#: field:stock.sale.forecast,product_uom_categ:0
msgid "Product UoM Category"
-msgstr ""
+msgstr "製品単位分類"
#. module: stock_planning
#: model:ir.actions.act_window,help:stock_planning.action_view_stock_sale_forecast_form
@@ -758,6 +781,8 @@ msgid ""
"manual procurement with this forecast when some periods are exceptional for "
"usual minimum stock rules."
msgstr ""
+"この受注予測数量は在庫計画者が調達を手動で行う、あるいは自動調達を補完するための表示です。幾つかの期間が通常の最小在庫ルールの例外である場合、この予測とと"
+"もに手動の調達を使うことができます。"
#. module: stock_planning
#: model:ir.actions.act_window,help:stock_planning.action_view_stock_planning_form
@@ -773,6 +798,10 @@ msgid ""
"can trigger the procurement of what is missing to reach your desired "
"quantities"
msgstr ""
+"マスタ調達スケジュールは倉庫の補充のための主な操縦者になることができ、または自動MRPスケジューリング(最小在庫ルール他)を補完します。\n"
+"各MPS行は現在と未来の在庫レベルを基本として、計画された在庫移動と同様、与えられた倉庫の中の与えられた在庫期間のために、与えられた製品の入庫と出庫の前も"
+"って計算された概観を与えます。予測数量は手動で変更することができます。そしてシミュレート結果の在庫数量に満足したなら、希望の数量に到達しないものの調達のき"
+"っかけとすることができます。"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:685
@@ -791,6 +820,17 @@ msgid ""
" Expected Out: %s Incoming Left: %s \n"
" Stock Simulation: %s Minimum stock: %s "
msgstr ""
+"MPSからユーザにより作成された集荷:%s 作成日:%s \n"
+" 期間:%s \n"
+" 状態に応じて: \n"
+" 倉庫予測:%s \n"
+" 初期在庫:%s \n"
+" 計画出庫:%s 計画入庫:%s \n"
+" 既出庫:%s 既入庫:%s \n"
+" 確認済出庫:%s 確認済入庫:%s \n"
+" 先行計画出庫:%s 先行確認済入庫:%s \n"
+" 期待出庫:%s 入庫残:%s \n"
+" 在庫シミュレーション:%s 最小在庫:%s "
#. module: stock_planning
#: field:stock.planning,period_id:0
@@ -798,48 +838,48 @@ msgstr ""
#: field:stock.sale.forecast,period_id:0
#: field:stock.sale.forecast.createlines,period_id:0
msgid "Period"
-msgstr ""
+msgstr "期間"
#. module: stock_planning
#: field:stock.sale.forecast,product_uos_categ:0
msgid "Product UoS Category"
-msgstr ""
+msgstr "製品販売単位分類"
#. module: stock_planning
#: field:stock.planning,active_uom:0
#: field:stock.sale.forecast,active_uom:0
msgid "Active UoM"
-msgstr ""
+msgstr "アクティブな単位"
#. module: stock_planning
#: view:stock.planning:0
msgid "Search Stock Planning"
-msgstr ""
+msgstr "在庫計画の検索"
#. module: stock_planning
#: field:stock.sale.forecast.createlines,copy_forecast:0
msgid "Copy Last Forecast"
-msgstr ""
+msgstr "最終予測のコピー"
#. module: stock_planning
#: help:stock.sale.forecast,product_id:0
msgid "Shows which product this forecast concerns."
-msgstr ""
+msgstr "この予測に関連する製品の表示"
#. module: stock_planning
#: selection:stock.planning,state:0
msgid "Done"
-msgstr ""
+msgstr "完了"
#. module: stock_planning
#: field:stock.period.createlines,period_ids:0
msgid "Periods"
-msgstr ""
+msgstr "期間"
#. module: stock_planning
#: model:ir.ui.menu,name:stock_planning.menu_stock_period_creatlines
msgid "Create Stock Periods"
-msgstr ""
+msgstr "在庫期間の作成"
#. module: stock_planning
#: view:stock.period:0
@@ -847,59 +887,59 @@ msgstr ""
#: view:stock.planning.createlines:0
#: view:stock.sale.forecast.createlines:0
msgid "Close"
-msgstr ""
+msgstr "閉じる"
#. module: stock_planning
#: view:stock.sale.forecast:0
#: selection:stock.sale.forecast,state:0
msgid "Validated"
-msgstr ""
+msgstr "検証済"
#. module: stock_planning
#: view:stock.period:0
#: selection:stock.period,state:0
msgid "Open"
-msgstr ""
+msgstr "開く"
#. module: stock_planning
#: help:stock.sale.forecast.createlines,copy_forecast:0
msgid "Copy quantities from last Stock and Sale Forecast."
-msgstr ""
+msgstr "最終在庫と受注予測から数量をコピー"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period1_per_dept:0
msgid "This Dept Period1"
-msgstr ""
+msgstr "この部門の期間1"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period3_per_dept:0
msgid "This Dept Period3"
-msgstr ""
+msgstr "この部門の期間3"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period2_per_dept:0
msgid "This Dept Period2"
-msgstr ""
+msgstr "この部門の期間2"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period5_per_dept:0
msgid "This Dept Period5"
-msgstr ""
+msgstr "この部門の期間5"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period4_per_dept:0
msgid "This Dept Period4"
-msgstr ""
+msgstr "この部門の期間4"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period2_per_warehouse:0
msgid "This Warehouse Period2"
-msgstr ""
+msgstr "この倉庫の期間2"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period3_per_warehouse:0
msgid "This Warehouse Period3"
-msgstr ""
+msgstr "この倉庫の期間3"
#. module: stock_planning
#: help:stock.planning,stock_supply_location:0
@@ -908,38 +948,39 @@ msgid ""
"supply will be made from Output location of Supply Warehouse. Used in "
"'Supply from Another Warehouse' with Supply Warehouse."
msgstr ""
+"供給倉庫の在庫場所から供給する場合はチェックします。チェックしない場合は供給倉庫の出力場所から供給されます。供給倉庫の他の倉庫場所から供給で使用されます。"
#. module: stock_planning
#: field:stock.sale.forecast,create_uid:0
msgid "Responsible"
-msgstr ""
+msgstr "担当"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Default UOM"
-msgstr ""
+msgstr "デフォルト単位"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period4_per_warehouse:0
msgid "This Warehouse Period4"
-msgstr ""
+msgstr "この倉庫の期間4"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period5_per_warehouse:0
msgid "This Warehouse Period5"
-msgstr ""
+msgstr "この倉庫の期間5"
#. module: stock_planning
#: view:stock.period:0
msgid "Current"
-msgstr ""
+msgstr "現在"
#. module: stock_planning
#: help:stock.planning,supply_warehouse_id:0
msgid ""
"Warehouse used as source in supply pick move created by 'Supply from Another "
"Warehouse'."
-msgstr ""
+msgstr "倉庫は、他の倉庫からの供給によって作成された、供給集荷移動の元として使用されます。"
#. module: stock_planning
#: model:ir.model,name:stock_planning.model_stock_planning
@@ -951,18 +992,18 @@ msgstr ""
msgid ""
"Shows which warehouse this forecast concerns. If during stock planning you "
"will need sales forecast for all warehouses choose any warehouse now."
-msgstr ""
+msgstr "この予測がどの倉庫に関連するかを表示します。在庫計画の期間に全ての倉庫の受注予測が必要な場合、今、倉庫を選択して下さい。"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:661
#, python-format
msgid "%s Procurement (%s, %s) %s %s \n"
-msgstr ""
+msgstr "%s 調達 (%s, %s) %s %s \n"
#. module: stock_planning
#: field:stock.sale.forecast,analyze_company:0
msgid "Per Company"
-msgstr ""
+msgstr "会社毎"
#. module: stock_planning
#: help:stock.planning,to_procure:0
@@ -970,42 +1011,42 @@ msgid ""
"Enter quantity which (by your plan) should come in. Change this value and "
"observe Stock simulation. This value should be equal or greater than "
"Confirmed In."
-msgstr ""
+msgstr "入庫すべき(計画による)数量を入力します。この値を変更し、在庫シミュレーションを観察します。この値は確認済入庫以上である必要があります。"
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_period4_per_company:0
msgid "This Company Period4"
-msgstr ""
+msgstr "この会社の期間4"
#. module: stock_planning
#: help:stock.planning.createlines,period_id:0
msgid "Period which planning will concern."
-msgstr ""
+msgstr "計画が関連する期間"
#. module: stock_planning
#: field:stock.planning,already_out:0
msgid "Already Out"
-msgstr ""
+msgstr "既出庫"
#. module: stock_planning
#: help:stock.planning,product_id:0
msgid "Product which this planning is created for."
-msgstr ""
+msgstr "この計画が作成される対象の製品"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Per Warehouse :"
-msgstr ""
+msgstr "倉庫毎:"
#. module: stock_planning
#: field:stock.planning,history:0
msgid "Procurement History"
-msgstr ""
+msgstr "調達履歴"
#. module: stock_planning
#: help:stock.period.createlines,date_start:0
msgid "Starting date for planning period."
-msgstr ""
+msgstr "開始期間の開始日"
#. module: stock_planning
#: model:ir.actions.act_window,name:stock_planning.action_stock_period_createlines_form
@@ -1015,48 +1056,48 @@ msgstr ""
#: view:stock.period:0
#: view:stock.period.createlines:0
msgid "Stock Periods"
-msgstr ""
+msgstr "在庫期間"
#. module: stock_planning
#: view:stock.planning:0
msgid "Stock"
-msgstr ""
+msgstr "在庫"
#. module: stock_planning
#: help:stock.planning,incoming:0
msgid "Quantity of all confirmed incoming moves in calculated Period."
-msgstr ""
+msgstr "計算された期間の全ての確認済入庫移動の数量"
#. module: stock_planning
#: field:stock.period,date_stop:0
#: field:stock.period.createlines,date_stop:0
msgid "End Date"
-msgstr ""
+msgstr "終了日"
#. module: stock_planning
#: view:stock.planning:0
msgid "No Requisition"
-msgstr ""
+msgstr "命令書なし"
#. module: stock_planning
#: field:stock.sale.forecast,name:0
msgid "Name"
-msgstr ""
+msgstr "名称"
#. module: stock_planning
#: help:stock.sale.forecast,period_id:0
msgid "Shows which period this forecast concerns."
-msgstr ""
+msgstr "この予測が関連する期間を表示"
#. module: stock_planning
#: field:stock.planning,product_uom:0
msgid "UoM"
-msgstr ""
+msgstr "単位"
#. module: stock_planning
#: view:stock.period:0
msgid "Closed Periods"
-msgstr ""
+msgstr "閉鎖済期間"
#. module: stock_planning
#: view:stock.planning:0
@@ -1064,26 +1105,26 @@ msgstr ""
#: view:stock.sale.forecast:0
#: field:stock.sale.forecast,product_id:0
msgid "Product"
-msgstr ""
+msgstr "製品"
#. module: stock_planning
#: model:ir.ui.menu,name:stock_planning.menu_stock_sale_forecast
#: model:ir.ui.menu,name:stock_planning.menu_stock_sale_forecast_all
#: view:stock.sale.forecast:0
msgid "Sales Forecasts"
-msgstr ""
+msgstr "受注予測"
#. module: stock_planning
#: field:stock.planning.createlines,product_categ_id:0
#: field:stock.sale.forecast.createlines,product_categ_id:0
msgid "Product Category"
-msgstr ""
+msgstr "製品分類"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:672
#, python-format
msgid "You must specify a Source Warehouse !"
-msgstr ""
+msgstr "元の倉庫を指定する必要があります。"
#. module: stock_planning
#: field:stock.planning,procure_to_stock:0
@@ -1100,7 +1141,7 @@ msgstr "承認"
msgid ""
"Period for this planning. Requisition will be created for beginning of the "
"period."
-msgstr "この計画の期間。申請は期間の開始時に作成されます。"
+msgstr "この計画の期間。命令書は期間の開始時に作成されます。"
#. module: stock_planning
#: code:addons/stock_planning/stock_planning.py:631
@@ -1143,7 +1184,7 @@ msgstr "誰がこの予測を作成したのか、検証したのかを示しま
#. module: stock_planning
#: field:stock.sale.forecast,analyzed_team_id:0
msgid "Sales Team"
-msgstr ""
+msgstr "販売チーム"
#. module: stock_planning
#: help:stock.planning,incoming_left:0
@@ -1152,6 +1193,8 @@ msgid ""
"between Planned In and Confirmed In. For current period Already In is also "
"calculated. This value is used to create procurement for lacking quantity."
msgstr ""
+"計画された入庫数量のために残された数量。これは計画入庫と確認済入庫の間の計算された差です。現在の期間のために、既入庫も計算されます。この値は不足数量のため"
+"に調達を生成するのに使用されます。"
#. module: stock_planning
#: help:stock.planning,outgoing_left:0
@@ -1159,12 +1202,12 @@ msgid ""
"Quantity expected to go out in selected period besides Confirmed Out. As a "
"difference between Planned Out and Confirmed Out. For current period Already "
"Out is also calculated"
-msgstr ""
+msgstr "確認済出庫とは別に選択された期間に出庫すると期待される数量。計画出庫と確認済出庫の差です。現在期間の既出庫もまた計算されます。"
#. module: stock_planning
#: view:stock.sale.forecast:0
msgid "Calculate Sales History"
-msgstr ""
+msgstr "受注履歴の計算"
#. module: stock_planning
#: model:ir.actions.act_window,help:stock_planning.action_stock_sale_forecast_createlines_form
@@ -1173,3 +1216,5 @@ msgid ""
"you only have to fill in the forecast quantities. The wizard doesn't "
"duplicate the line when another one exist for the same selection."
msgstr ""
+"このウィザードは一度に複数の予測行を作成するのを手助けします。それが作成された後、あなたは予測数量を埋める必要があります。同じ選択に対して同じものが存在す"
+"る場合、ウィザードは行を重複させません。"
diff --git a/addons/stock_planning/wizard/stock_planning_create_periods_view.xml b/addons/stock_planning/wizard/stock_planning_create_periods_view.xml
index db78799f000..e65f378a638 100644
--- a/addons/stock_planning/wizard/stock_planning_create_periods_view.xml
+++ b/addons/stock_planning/wizard/stock_planning_create_periods_view.xml
@@ -9,7 +9,11 @@
form
-
+
+
+
+
+
-
-
-
-
+
diff --git a/addons/stock_planning/wizard/stock_planning_createlines.py b/addons/stock_planning/wizard/stock_planning_createlines.py
index a6e12ad4bc7..3d43241341d 100644
--- a/addons/stock_planning/wizard/stock_planning_createlines.py
+++ b/addons/stock_planning/wizard/stock_planning_createlines.py
@@ -56,7 +56,6 @@ class stock_planning_createlines(osv.osv_memory):
planning_obj = self.pool.get('stock.planning')
mod_obj = self.pool.get('ir.model.data')
prod_categ_obj = self.pool.get('product.category')
- template_obj = self.pool.get('product.template')
planning_lines = []
for f in self.browse(cr, uid, ids, context=context):
if f.forecasted_products:
@@ -67,8 +66,7 @@ class stock_planning_createlines(osv.osv_memory):
else:
categ_ids = f.product_categ_id.id and [f.product_categ_id.id] or []
prod_categ_ids = prod_categ_obj.search(cr,uid,[('parent_id','child_of',categ_ids)])
- templates_ids = template_obj.search(cr,uid,[('categ_id','in',prod_categ_ids)])
- products_id1 = product_obj.search(cr,uid,[('product_tmpl_id','in',templates_ids)])
+ products_id1 = product_obj.search(cr,uid,[('categ_id','in',prod_categ_ids)])
if len(products_id1)==0:
raise osv.except_osv(_('Error !'), _('No forecasts for selected period or no products in selected category !'))
diff --git a/addons/stock_planning/wizard/stock_planning_createlines_view.xml b/addons/stock_planning/wizard/stock_planning_createlines_view.xml
index e51ab4a3ba0..458994621c1 100644
--- a/addons/stock_planning/wizard/stock_planning_createlines_view.xml
+++ b/addons/stock_planning/wizard/stock_planning_createlines_view.xml
@@ -8,11 +8,6 @@
form
-
-
- or
-
-
@@ -20,6 +15,11 @@
+
diff --git a/addons/stock_planning/wizard/stock_planning_forecast.py b/addons/stock_planning/wizard/stock_planning_forecast.py
index 9f73cf257eb..c72ac0599ea 100644
--- a/addons/stock_planning/wizard/stock_planning_forecast.py
+++ b/addons/stock_planning/wizard/stock_planning_forecast.py
@@ -49,13 +49,11 @@ class stock_sale_forecast_createlines(osv.osv_memory):
forecast_obj = self.pool.get('stock.sale.forecast')
mod_obj = self.pool.get('ir.model.data')
prod_categ_obj = self.pool.get('product.category')
- template_obj = self.pool.get('product.template')
forecast_lines = []
for f in self.browse(cr, uid, ids, context=context):
categ_ids = f.product_categ_id.id and [f.product_categ_id.id] or []
prod_categ_ids = prod_categ_obj.search(cr, uid, [('parent_id','child_of', categ_ids)])
- templates_ids = template_obj.search(cr, uid, [('categ_id','in',prod_categ_ids)])
- products_ids = product_obj.search(cr, uid, [('product_tmpl_id','in',templates_ids)])
+ products_ids = product_obj.search(cr, uid, [('categ_id','in',prod_categ_ids)])
if len(products_ids) == 0:
raise osv.except_osv(_('Error !'), _('No products in selected category !'))
copy = f.copy_forecast
diff --git a/addons/stock_planning/wizard/stock_planning_forecast_view.xml b/addons/stock_planning/wizard/stock_planning_forecast_view.xml
index 3c31404a070..0f3018350c0 100644
--- a/addons/stock_planning/wizard/stock_planning_forecast_view.xml
+++ b/addons/stock_planning/wizard/stock_planning_forecast_view.xml
@@ -9,11 +9,6 @@
form