[MERGE] forward port of branch 8.0 up to 030b157
This commit is contained in:
@@ -5,7 +5,8 @@ from passlib.context import CryptContext
|
||||
import openerp
|
||||
from openerp.osv import fields, osv
|
||||
|
||||
openerp.addons.base.res.res_users.USER_PRIVATE_FIELDS.append('password_crypt')
|
||||
from openerp.addons.base.res import res_users
|
||||
res_users.USER_PRIVATE_FIELDS.append('password_crypt')
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class SignupError(Exception):
|
||||
def random_token():
|
||||
# the token has an entropy of about 120 bits (6 bits/char * 20 chars)
|
||||
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
return ''.join(random.choice(chars) for i in xrange(20))
|
||||
return ''.join(random.SystemRandom().choice(chars) for i in xrange(20))
|
||||
|
||||
def now(**kwargs):
|
||||
dt = datetime.now() + timedelta(**kwargs)
|
||||
|
||||
@@ -574,7 +574,7 @@ class calendar_alarm(osv.Model):
|
||||
'type': fields.selection([('notification', 'Notification'), ('email', 'Email')], 'Type', required=True),
|
||||
'duration': fields.integer('Amount', required=True),
|
||||
'interval': fields.selection([('minutes', 'Minutes'), ('hours', 'Hours'), ('days', 'Days')], 'Unit', required=True),
|
||||
'duration_minutes': fields.function(_get_duration, type='integer', string='duration_minutes', store=True),
|
||||
'duration_minutes': fields.function(_get_duration, type='integer', string='Duration in minutes', store=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -961,7 +961,7 @@ class calendar_event(osv.Model):
|
||||
|
||||
'user_id': fields.many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}),
|
||||
'color_partner_id': fields.related('user_id', 'partner_id', 'id', type="integer", string="colorize", store=False), # Color of creator
|
||||
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the event alarm information without removing it."),
|
||||
'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the event alarm information without removing it."),
|
||||
'categ_ids': fields.many2many('calendar.event.type', 'meeting_category_rel', 'event_id', 'type_id', 'Tags'),
|
||||
'attendee_ids': fields.one2many('calendar.attendee', 'event_id', 'Attendees', ondelete='cascade'),
|
||||
'partner_ids': fields.many2many('res.partner', 'calendar_event_res_partner_rel', string='Attendees', states={'done': [('readonly', True)]}),
|
||||
|
||||
@@ -1441,7 +1441,7 @@ msgstr ""
|
||||
|
||||
#. module: calendar
|
||||
#: field:calendar.alarm,duration_minutes:0
|
||||
msgid "duration_minutes"
|
||||
msgid "Duration in minutes"
|
||||
msgstr ""
|
||||
|
||||
#. module: calendar
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ class pad_common(osv.osv_memory):
|
||||
pad["server"] = pad["server"].rstrip('/')
|
||||
# generate a salt
|
||||
s = string.ascii_uppercase + string.digits
|
||||
salt = ''.join([s[random.randint(0, len(s) - 1)] for i in range(10)])
|
||||
salt = ''.join([s[random.SystemRandom().randint(0, len(s) - 1)] for i in range(10)])
|
||||
#path
|
||||
# etherpad hardcodes pad id length limit to 50
|
||||
path = '-%s-%s' % (self._name, salt)
|
||||
|
||||
@@ -3865,6 +3865,13 @@ msgstr ""
|
||||
msgid "Unknown Barcode"
|
||||
msgstr ""
|
||||
|
||||
#. module: point_of_sale
|
||||
#. openerp-web
|
||||
#: code:addons/point_of_sale/static/src/xml/pos.xml:914
|
||||
#, python-format
|
||||
msgid "Unknown Customer"
|
||||
msgstr ""
|
||||
|
||||
#. module: point_of_sale
|
||||
#. openerp-web
|
||||
#: code:addons/point_of_sale/static/src/xml/pos.xml:845
|
||||
|
||||
@@ -1208,9 +1208,10 @@
|
||||
</span>
|
||||
<t t-if="order.get_client()">
|
||||
<i class='fa fa-user'/>
|
||||
<t t-esc="widget.order.get_client_name()"/>
|
||||
</t>
|
||||
<t t-esc="(order.get_client() ? order.get_client_name()+' : ':'') + moment(order.creation_date).format('hh:mm')"/>
|
||||
</span>
|
||||
<t t-if="!order.get_client()">Unknown Customer</t>:
|
||||
<t t-esc="order.get('creationDate').toString('t')"/>
|
||||
</t>
|
||||
<t t-if='order !== widget.pos.get_order()'>
|
||||
<span class="order-button select-order" t-att-data-uid="order.uid">
|
||||
|
||||
@@ -3264,11 +3264,6 @@ msgstr ""
|
||||
msgid "lb(s)"
|
||||
msgstr ""
|
||||
|
||||
#. module: product
|
||||
#: view:product.product:product.product_normal_form_view
|
||||
msgid "lst_price"
|
||||
msgstr ""
|
||||
|
||||
#. module: product
|
||||
#: model:product.uom,name:product.product_uom_mile
|
||||
msgid "mile(s)"
|
||||
|
||||
@@ -27,6 +27,39 @@ from openerp.osv import fields, osv
|
||||
class product_product(osv.osv):
|
||||
_inherit = "product.product"
|
||||
|
||||
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True):
|
||||
"""
|
||||
Inherit read_group to calculate the sum of the non-stored fields, as it is not automatically done anymore through the XML.
|
||||
"""
|
||||
res = super(product_product, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby, lazy=lazy)
|
||||
if context is None:
|
||||
context = {}
|
||||
fields_list = ['turnover', 'sale_avg_price', 'sale_purchase_price', 'sale_num_invoiced', 'purchase_num_invoiced',
|
||||
'sales_gap', 'purchase_gap', 'total_cost', 'sale_expected', 'normal_cost', 'total_margin',
|
||||
'expected_margin', 'total_margin_rate', 'expected_margin_rate']
|
||||
if any(x in fields for x in fields_list):
|
||||
# Calculate first for every product in which line it needs to be applied
|
||||
re_ind = 0
|
||||
prod_re = {}
|
||||
tot_products = []
|
||||
for re in res:
|
||||
if re.get('__domain'):
|
||||
products = self.search(cr, uid, re['__domain'], context=context)
|
||||
tot_products += products
|
||||
for prod in products:
|
||||
prod_re[prod] = re_ind
|
||||
re_ind += 1
|
||||
|
||||
res_val = self._product_margin(cr, uid, tot_products, [x for x in fields if fields in fields_list], '', context=context)
|
||||
for key in res_val.keys():
|
||||
for l in res_val[key].keys():
|
||||
re = res[prod_re[key]]
|
||||
if re.get(l):
|
||||
re[l] += res_val[key][l]
|
||||
else:
|
||||
re[l] = res_val[key][l]
|
||||
return res
|
||||
|
||||
def _product_margin(self, cr, uid, ids, field_names, arg, context=None):
|
||||
res = {}
|
||||
if context is None:
|
||||
@@ -65,7 +98,7 @@ class product_product(osv.osv):
|
||||
from account_invoice_line l
|
||||
left join account_invoice i on (l.invoice_id = i.id)
|
||||
left join product_product product on (product.id=l.product_id)
|
||||
left join product_template pt on (pt.id = l.product_id)
|
||||
left join product_template pt on (pt.id = product.product_tmpl_id)
|
||||
left join product_uom pu on (pt.uom_id = pu.id)
|
||||
left join product_uom pu2 on (l.uos_id = pu2.id)
|
||||
where l.product_id = %s and i.state in %s and i.type IN %s and (i.date_invoice IS NULL or (i.date_invoice>=%s and i.date_invoice<=%s and i.company_id=%s))
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="priority" eval="50"/>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Product Margins" type="bar">
|
||||
<field name="name"/>
|
||||
<field name="product_tmpl_id"/>
|
||||
<field name="turnover" operator="+"/>
|
||||
<field name="total_cost" operator="+"/>
|
||||
</graph>
|
||||
|
||||
@@ -1107,6 +1107,9 @@ class purchase_order_line(osv.osv):
|
||||
|
||||
res = {'value': {'price_unit': price_unit or 0.0, 'name': name or '', 'product_uom' : uom_id or False}}
|
||||
if not product_id:
|
||||
if not uom_id:
|
||||
uom_id = self.default_get(cr, uid, ['product_uom'], context=context).get('product_uom', False)
|
||||
res['value']['product_uom'] = uom_id
|
||||
return res
|
||||
|
||||
product_product = self.pool.get('product.product')
|
||||
|
||||
@@ -90,7 +90,7 @@ class crm_team(osv.Model):
|
||||
'complete_name': fields.function(get_full_name, type='char', size=256, readonly=True, store=True, string="Full Name"),
|
||||
'code': fields.char('Code', size=8),
|
||||
'active': fields.boolean('Active', help="If the active field is set to "\
|
||||
"true, it will allow you to hide the sales team without removing it."),
|
||||
"false, it will allow you to hide the sales team without removing it."),
|
||||
'change_responsible': fields.boolean('Reassign Escalated', help="When escalating to this team override the salesman with the team leader."),
|
||||
'user_id': fields.many2one('res.users', 'Team Leader'),
|
||||
'member_ids': fields.many2many('res.users', 'sale_member_rel', 'team_id', 'member_id', 'Team Members'),
|
||||
|
||||
@@ -48,7 +48,7 @@ DOMAIN_ALL = [(1, '=', 1)]
|
||||
# A good selection of easy to read password characters (e.g. no '0' vs 'O', etc.)
|
||||
RANDOM_PASS_CHARACTERS = 'aaaabcdeeeefghjkmnpqrstuvwxyzAAAABCDEEEEFGHJKLMNPQRSTUVWXYZ23456789'
|
||||
def generate_random_pass():
|
||||
return ''.join(random.sample(RANDOM_PASS_CHARACTERS,10))
|
||||
return ''.join(random.SystemRandom().sample(RANDOM_PASS_CHARACTERS,10))
|
||||
|
||||
class share_wizard(osv.TransientModel):
|
||||
_name = 'share.wizard'
|
||||
|
||||
@@ -1067,6 +1067,9 @@
|
||||
<group name="quants_grp" string="Reserved Quants" colspan="4" groups="base.group_no_one">
|
||||
<field name="reserved_quant_ids" nolabel="1"/>
|
||||
</group>
|
||||
<group name="moved_quants_grp" string="Moved Quants" colspan="4" groups="base.group_no_one" attrs="{'invisible': [('state', '!=', 'done')]}">
|
||||
<field name="quant_ids" readonly="1" nolabel="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
@@ -1121,7 +1124,10 @@
|
||||
<field name="location_dest_id" domain="[('usage','<>','view')]"/>
|
||||
</group>
|
||||
<group name="quants_grp" string="Reserved Quants" colspan="4" groups="base.group_no_one">
|
||||
<field name="reserved_quant_ids"/>
|
||||
<field name="reserved_quant_ids" nolabel="1"/>
|
||||
</group>
|
||||
<group name="moved_quants_grp" string="Moved Quants" colspan="4" groups="base.group_no_one" attrs="{'invisible': [('state', '!=', 'done')]}">
|
||||
<field name="quant_ids" readonly="1" nolabel="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
|
||||
@@ -338,6 +338,9 @@ class website_sale(http.Controller):
|
||||
return {}
|
||||
|
||||
value = order._cart_update(product_id=product_id, line_id=line_id, add_qty=add_qty, set_qty=set_qty)
|
||||
if not order.cart_quantity:
|
||||
request.website.sale_reset()
|
||||
return {}
|
||||
if not display:
|
||||
return None
|
||||
value['cart_quantity'] = order.cart_quantity
|
||||
|
||||
@@ -60,7 +60,7 @@ $(document).ready(function () {
|
||||
}
|
||||
|
||||
function track_ga() {
|
||||
website_ga = this._gaw || function(){};
|
||||
website_ga = this.ga || function(){};
|
||||
website_ga.apply(this, arguments);
|
||||
}
|
||||
|
||||
|
||||
@@ -484,7 +484,7 @@ class module(osv.osv):
|
||||
ir_model_data = self.pool.get('ir.model.data')
|
||||
modules_to_remove = [m.name for m in self.browse(cr, uid, ids, context)]
|
||||
ir_model_data._module_data_uninstall(cr, uid, modules_to_remove, context)
|
||||
self.write(cr, uid, ids, {'state': 'uninstalled'})
|
||||
self.write(cr, uid, ids, {'state': 'uninstalled', 'latest_version': False})
|
||||
return True
|
||||
|
||||
def downstream_dependencies(self, cr, uid, ids, known_dep_ids=None,
|
||||
|
||||
@@ -141,7 +141,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||
migrations.migrate_module(package, 'pre')
|
||||
load_openerp_module(package.name)
|
||||
|
||||
new_install = package.installed_version is None
|
||||
new_install = package.state == 'to install'
|
||||
if new_install:
|
||||
py_module = sys.modules['openerp.addons.%s' % (module_name,)]
|
||||
pre_init = package.info.get('pre_init_hook')
|
||||
|
||||
Reference in New Issue
Block a user