[MERGE] forward port of branch 8.0 up to ed3065e

This commit is contained in:
Christophe Simonis
2015-06-18 19:41:31 +02:00
44 changed files with 321 additions and 93 deletions
+2 -2
View File
@@ -1326,9 +1326,9 @@ class account_invoice_line(models.Model):
raise UserError(_("You must first select a partner!"))
if not product:
if type in ('in_invoice', 'in_refund'):
return {'value': {}, 'domain': {'product_uom': []}}
return {'value': {}, 'domain': {'uos_id': []}}
else:
return {'value': {'price_unit': 0.0}, 'domain': {'product_uom': []}}
return {'value': {'price_unit': 0.0}, 'domain': {'uos_id': []}}
values = {}
+1 -1
View File
@@ -39,7 +39,7 @@
</tr>
</thead>
<tbody>
<tr t-foreach="get_lines(data['form']['based_on'], data['form']['company_id'])" t-as="taxline">
<tr t-foreach="get_lines(data['form']['based_on'], data['form']['company_id'], data['form']['chart_tax_id'])" t-as="taxline">
<t t-if="len(taxline['level']) > 5">
<t t-set="style" t-value="'font-weight:normal;'"/>
</t>
+1
View File
@@ -114,6 +114,7 @@ class AuthSignupHome(openerp.addons.web.controllers.main.Home):
values = dict((key, qcontext.get(key)) for key in ('login', 'name', 'password'))
assert any([k for k in values.values()]), "The form was not properly filled in."
assert values.get('password') == qcontext.get('confirm_password'), "Passwords do not match; please retype them."
values['lang'] = request.lang
self._signup_with_values(qcontext.get('token'), values)
request.cr.commit()
+5 -5
View File
@@ -657,18 +657,18 @@ class ir_model(osv.Model):
original_exp_report = openerp.service.report.exp_report
def exp_report(db, uid, object, ids, data=None, context=None):
def exp_report(db, uid, object, ids, datas=None, context=None):
"""
Export Report
"""
if object == 'printscreen.list':
original_exp_report(db, uid, object, ids, data, context)
original_exp_report(db, uid, object, ids, datas, context)
new_ids = []
for id in ids:
new_ids.append(calendar_id2real_id(id))
if data.get('id', False):
data['id'] = calendar_id2real_id(data['id'])
return original_exp_report(db, uid, object, new_ids, data, context)
if datas.get('id', False):
datas['id'] = calendar_id2real_id(datas['id'])
return original_exp_report(db, uid, object, new_ids, datas, context)
openerp.service.report.exp_report = exp_report
+1
View File
@@ -8,6 +8,7 @@
<field name="name">Declarantnum</field>
<field name="code">declarantnum</field>
<field name="padding">5</field>
<field name="company_id" eval="False"/>
</record>
</data>
+12 -9
View File
@@ -388,13 +388,6 @@ class mail_thread(osv.AbstractModel):
name = ir_model_pool.read(cr, uid, ids, ['name'], context=context)[0]['name']
self.message_post(cr, uid, thread_id, body=_('%s created') % name, context=context)
# auto_subscribe: take values and defaults into account
create_values = dict(values)
for key, val in context.iteritems():
if key.startswith('default_') and key[8:] not in create_values:
create_values[key[8:]] = val
self.message_auto_subscribe(cr, uid, [thread_id], create_values.keys(), context=context, values=create_values)
# track values
track_ctx = dict(context)
if 'lang' not in track_ctx:
@@ -404,6 +397,14 @@ class mail_thread(osv.AbstractModel):
if tracked_fields:
initial_values = {thread_id: dict.fromkeys(tracked_fields, False)}
self.message_track(cr, uid, [thread_id], tracked_fields, initial_values, context=track_ctx)
# auto_subscribe: take values and defaults into account
create_values = dict(values)
for key, val in context.iteritems():
if key.startswith('default_') and key[8:] not in create_values:
create_values[key[8:]] = val
self.message_auto_subscribe(cr, uid, [thread_id], create_values.keys(), context=context, values=create_values)
return thread_id
def write(self, cr, uid, ids, values, context=None):
@@ -428,14 +429,16 @@ class mail_thread(osv.AbstractModel):
initial_values = dict((record.id, dict((key, getattr(record, key)) for key in tracked_fields))
for record in records)
# Perform write, update followers
# Perform write
result = super(mail_thread, self).write(cr, uid, ids, values, context=context)
self.message_auto_subscribe(cr, uid, ids, values.keys(), context=context, values=values)
# Perform the tracking
if tracked_fields:
self.message_track(cr, uid, ids, tracked_fields, initial_values, context=track_ctx)
# update followers
self.message_auto_subscribe(cr, uid, ids, values.keys(), context=context, values=values)
return result
def unlink(self, cr, uid, ids, context=None):
+2 -1
View File
@@ -157,7 +157,8 @@
<field name="priority">50</field>
<field name="arch" type="xml">
<search string="Membership Partners">
<field name="name" string="Members"/>
<field name="name"
filter_domain="['|','|',('name','ilike',self),('parent_id','ilike',self),('ref','=',self)]"/>
<field name="category_id"/>
<field name="membership_start" invisible="1"/>
<field name="membership_stop" string="End Membership Date"/>
+2 -2
View File
@@ -975,7 +975,7 @@ class mrp_production(osv.osv):
location_id=produce_product.location_id.id, restrict_lot_id=lot_id, context=context)
stock_mov_obj.write(cr, uid, new_moves, {'production_id': production_id}, context=context)
remaining_qty = subproduct_factor * production_qty_uom - qty
if not float_is_zero(remaining_qty, precision_rounding=precision):
if not float_is_zero(remaining_qty, precision_digits=precision):
# In case you need to make more than planned
#consumed more in wizard than previously planned
extra_move_id = stock_mov_obj.copy(cr, uid, produce_product.id, default={'product_uom_qty': remaining_qty,
@@ -1006,7 +1006,7 @@ class mrp_production(osv.osv):
stock_mov_obj.action_consume(cr, uid, [raw_material_line.id], consumed_qty, raw_material_line.location_id.id,
restrict_lot_id=consume['lot_id'], consumed_for=main_production_move, context=context)
remaining_qty -= consumed_qty
if not float_is_zero(remaining_qty, precision_rounding=precision):
if not float_is_zero(remaining_qty, precision_digits=precision):
#consumed more in wizard than previously planned
product = self.pool.get('product.product').browse(cr, uid, consume['product_id'], context=context)
extra_move_id = self._make_consume_line_from_data(cr, uid, production, product, product.uom_id.id, remaining_qty, False, 0, context=context)
+15 -5
View File
@@ -576,6 +576,16 @@ class pos_order(osv.osv):
_description = "Point of Sale"
_order = "id desc"
def _amount_line_tax(self, cr, uid, line, context=None):
account_tax_obj = self.pool['account.tax']
taxes_ids = [tax for tax in line.product_id.taxes_id if tax.company_id.id == line.order_id.company_id.id]
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
taxes = account_tax_obj.compute_all(cr, uid, taxes_ids, price, line.qty, product=line.product_id, partner=line.order_id.partner_id or False)['taxes']
val = 0.0
for c in taxes:
val += c.get('amount', 0.0)
return val
def _order_fields(self, cr, uid, ui_order, context=None):
process_line = partial(self.pool['pos.order.line']._order_line_fields, cr, uid, context=context)
return {
@@ -695,10 +705,10 @@ class pos_order(osv.osv):
res[order.id]['amount_paid'] += payment.amount
res[order.id]['amount_return'] += (payment.amount < 0 and payment.amount or 0)
for line in order.lines:
val1 += line.price_subtotal_incl
val1 += self._amount_line_tax(cr, uid, line, context=context)
val2 += line.price_subtotal
res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val1-val2)
res[order.id]['amount_total'] = cur_obj.round(cr, uid, cur, val1)
res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val1)
res[order.id]['amount_total'] = cur_obj.round(cr, uid, cur, val1+val2)
return res
_columns = {
@@ -1321,8 +1331,8 @@ class pos_order_line(osv.osv):
taxes = account_tax_obj.compute_all(cr, uid, taxes_ids, price, line.qty, product=line.product_id, partner=line.order_id.partner_id or False)
cur = line.order_id.pricelist_id.currency_id
res[line.id]['price_subtotal'] = cur_obj.round(cr, uid, cur, taxes['total'])
res[line.id]['price_subtotal_incl'] = cur_obj.round(cr, uid, cur, taxes['total_included'])
res[line.id]['price_subtotal'] = taxes['total']
res[line.id]['price_subtotal_incl'] = taxes['total_included']
return res
def onchange_product_id(self, cr, uid, ids, pricelist, product_id, qty=0, partner_id=False, context=None):
+112
View File
@@ -65,6 +65,10 @@
<field name="name">Food</field>
<field name="image" type="base64" file="point_of_sale/static/img/food-image.jpg"/>
</record>
<record id="partner_services" model="pos.category">
<field name="name">Partner Services</field>
<field name="image" type="base64" file="point_of_sale/static/img/partners/services.jpg"/>
</record>
<record id="fruits" model="pos.category">
<field name="name">Fresh Fruits</field>
<field name="image" type="base64" file="point_of_sale/static/img/fruits-image.jpg"/>
@@ -1085,6 +1089,114 @@
<field name="pos_categ_id" ref="food"/>
<field name="image" type="base64" file="point_of_sale/static/img/ijsboerke_dame_blanche_2,5l-image.jpg"/>
</record>
<record id="partner_product_1" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">850.00</field>
<field name="name">Odoo Start Workshop</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/openbig.jpg"/>
</record>
<record id="partner_product_2" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">999.99</field>
<field name="name">Odoo Consulting</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/bhc.jpg"/>
</record>
<record id="partner_product_3" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">999.99</field>
<field name="name">Eezee-It</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/eezee-it.png"/>
</record>
<record id="partner_product_4" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">999.99</field>
<field name="name">Ekomurz.nl</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/ekomurz.gif"/>
</record>
<record id="partner_product_5" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">999.99</field>
<field name="name">Acsone.eu</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/acsone.png"/>
</record>
<record id="partner_product_6" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">999.99</field>
<field name="name">Vauxoo.com</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/vauxoo.png"/>
</record>
<record id="partner_product_7" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">999.99</field>
<field name="name">Datalp.com</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/datalp.jpg"/>
</record>
<record id="partner_product_8" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">999.99</field>
<field name="name">camptocamp.com</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/camptocamp.png"/>
</record>
<record id="partner_product_9" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">999.99</field>
<field name="name">EGGS-solutions.fr</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/eggs-solutions.jpg"/>
</record>
<record id="partner_product_10" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">3500.00</field>
<field name="name">Odoo primary scoping &amp; analysis package (£900, £450, £30)</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/opusvl.png"/>
</record>
<record id="partner_product_11" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">900.00</field>
<field name="name">3rd party system analysis</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/opusvl.png"/>
</record>
<record id="partner_product_12" model="product.product">
<field name="available_in_pos">True</field>
<field name="list_price">30.00</field>
<field name="name">Odoo enterprise agreement</field>
<field name="type">service</field>
<field name="pos_categ_id" ref="partner_services"/>
<field name="image" type="base64" file="point_of_sale/static/img/partners/opusvl.png"/>
</record>
<!-- The electronic products shouldn't be present in the point of sale for the demo -->
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

+12 -15
View File
@@ -25,8 +25,7 @@ import time
from _common import ceiling
from openerp import SUPERUSER_ID
from openerp import tools
from openerp import api, tools, SUPERUSER_ID
from openerp.osv import osv, fields, expression
from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
@@ -225,19 +224,17 @@ class product_ul(osv.osv):
#----------------------------------------------------------
class product_category(osv.osv):
def name_get(self, cr, uid, ids, context=None):
if isinstance(ids, (list, tuple)) and not len(ids):
return []
if isinstance(ids, (long, int)):
ids = [ids]
reads = self.read(cr, uid, ids, ['name','parent_id'], context=context)
res = []
for record in reads:
name = record['name']
if record['parent_id']:
name = record['parent_id'][1]+' / '+name
res.append((record['id'], name))
return res
@api.multi
def name_get(self):
def get_names(cat):
""" Return the list [cat.name, cat.parent_id.name, ...] """
res = []
while cat:
res.append(cat.name)
cat = cat.parent_id
return res
return [(cat.id, " / ".join(reversed(get_names(cat)))) for cat in self]
def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
if not args:
+6 -2
View File
@@ -1259,8 +1259,12 @@ class procurement_order(osv.osv):
return super(procurement_order, self).run(cr, uid, list(set_others), context=context)
def _check(self, cr, uid, procurement, context=None):
if procurement.purchase_line_id and procurement.purchase_line_id.order_id.shipped: # TOCHECK: does it work for several deliveries?
return True
if procurement.purchase_line_id:
if procurement.purchase_line_id.order_id.shipped:
return True
elif procurement.move_ids:
moves = self.pool.get('stock.move').browse(cr, uid, [x.id for x in procurement.move_ids], context=context)
return all(move.state == 'done' for move in moves)
return super(procurement_order, self)._check(cr, uid, procurement, context=context)
def _check_supplier_info(self, cr, uid, ids, context=None):
+5 -6
View File
@@ -295,12 +295,11 @@ class sale_order(osv.osv):
def onchange_delivery_id(self, cr, uid, ids, company_id, partner_id, delivery_id, fiscal_position, context=None):
r = {'value': {}}
if not fiscal_position:
if not company_id:
company_id = self._get_default_company(cr, uid, context=context)
fiscal_position = self.pool['account.fiscal.position'].get_fiscal_position(cr, uid, company_id, partner_id, delivery_id, context=context)
if fiscal_position:
r['value']['fiscal_position'] = fiscal_position
if not company_id:
company_id = self._get_default_company(cr, uid, context=context)
fiscal_position = self.pool['account.fiscal.position'].get_fiscal_position(cr, uid, company_id, partner_id, delivery_id, context=context)
if fiscal_position:
r['value']['fiscal_position'] = fiscal_position
return r
def onchange_partner_id(self, cr, uid, ids, part, context=None):
+15 -8
View File
@@ -1952,7 +1952,7 @@ class stock_move(osv.osv):
self.write(cr, uid, [move.id], {'state': 'confirmed'}, context=context)
def _prepare_procurement_from_move(self, cr, uid, move, context=None):
origin = (move.group_id and (move.group_id.name + ":") or "") + (move.rule_id and move.rule_id.name or move.origin or "/")
origin = (move.group_id and (move.group_id.name + ":") or "") + (move.rule_id and move.rule_id.name or move.origin or move.picking_id.name or "/")
group_id = move.group_id and move.group_id.id or False
if move.rule_id:
if move.rule_id.group_propagation_option == 'fixed' and move.rule_id.group_id:
@@ -2155,6 +2155,19 @@ class stock_move(osv.osv):
result['location_dest_id'] = loc_dest_id
return {'value': result}
def _prepare_picking_assign(self, cr, uid, move, context=None):
""" Prepares a new picking for this move as it could not be assigned to
another picking. This method is designed to be inherited.
"""
values = {
'origin': move.origin,
'company_id': move.company_id and move.company_id.id or False,
'move_type': move.group_id and move.group_id.move_type or 'direct',
'partner_id': move.partner_id.id or False,
'picking_type_id': move.picking_type_id and move.picking_type_id.id or False,
}
return values
@api.cr_uid_ids_context
def _picking_assign(self, cr, uid, move_ids, procurement_group, location_from, location_to, context=None):
"""Assign a picking on the given move_ids, which is a list of move supposed to share the same procurement_group, location_from and location_to
@@ -2170,13 +2183,7 @@ class stock_move(osv.osv):
pick = picks[0]
else:
move = self.browse(cr, uid, move_ids, context=context)[0]
values = {
'origin': move.origin,
'company_id': move.company_id and move.company_id.id or False,
'move_type': move.group_id and move.group_id.move_type or 'direct',
'partner_id': move.partner_id.id or False,
'picking_type_id': move.picking_type_id and move.picking_type_id.id or False,
}
values = self._prepare_picking_assign(cr, uid, move, context=context)
pick = pick_obj.create(cr, uid, values, context=context)
return self.write(cr, uid, move_ids, {'picking_id': pick}, context=context)
@@ -46,21 +46,39 @@ class stock_history(osv.osv):
if context is None:
context = {}
date = context.get('history_date')
prod_dict = {}
if 'inventory_value' in fields:
group_lines = {}
for line in res:
domain = line.get('__domain', [])
group_lines.setdefault(str(domain), self.search(cr, uid, domain, context=context))
line_ids = set()
for ids in group_lines.values():
for product_id in ids:
line_ids.add(product_id)
line_ids = list(line_ids)
cr.execute('SELECT id, product_id, price_unit_on_quant, company_id, quantity FROM stock_history WHERE id in %s', (tuple(line_ids),))
lines_rec = cr.dictfetchall()
lines_dict = dict((line['id'], line) for line in lines_rec)
product_ids = list(set(line_rec['product_id'] for line_rec in lines_rec))
products_rec = self.pool['product.product'].read(cr, uid, product_ids, ['cost_method', 'product_tmpl_id'], context=context)
products_dict = dict((product['id'], product) for product in products_rec)
cost_method_product_tmpl_ids = list(set(product['product_tmpl_id'][0] for product in products_rec if product['cost_method'] != 'real'))
cr.execute('SELECT DISTINCT ON (product_template_id, company_id) product_template_id, company_id, cost FROM product_price_history WHERE product_template_id in %s AND datetime <= %s ORDER BY product_template_id, company_id, datetime DESC', (tuple(cost_method_product_tmpl_ids), date))
histories = cr.dictfetchall()
histories_dict = {}
for history in histories:
histories_dict[(history['product_template_id'], history['company_id'])] = history['cost']
for line in res:
lines = self.search(cr, uid, line.get('__domain', []), context=context)
inv_value = 0.0
product_tmpl_obj = self.pool.get("product.template")
lines_rec = self.browse(cr, uid, lines, context=context)
for line_rec in lines_rec:
if line_rec.product_id.cost_method == 'real':
price = line_rec.price_unit_on_quant
lines = group_lines.get(str(line.get('__domain', [])))
for line_id in lines:
line_rec = lines_dict[line_id]
product = products_dict[line_rec['product_id']]
if product['cost_method'] == 'real':
price = line_rec['price_unit_on_quant']
else:
if not line_rec.product_id.id in prod_dict:
prod_dict[line_rec.product_id.id] = product_tmpl_obj.get_history_price(cr, uid, line_rec.product_id.product_tmpl_id.id, line_rec.company_id.id, date=date, context=context)
price = prod_dict[line_rec.product_id.id]
inv_value += price * line_rec.quantity
price = histories_dict.get((product['product_tmpl_id'][0], line_rec['company_id']), 0.0)
inv_value += price * line_rec['quantity']
line['inventory_value'] = inv_value
return res
+4 -4
View File
@@ -312,12 +312,12 @@ def set_cookie_and_redirect(redirect_url):
def login_redirect():
url = '/web/login?'
if request.debug:
url += 'debug&'
# built the redirect url, keeping all the query parameters of the url
redirect_url = '%s?%s' % (request.httprequest.base_url, werkzeug.urls.url_encode(request.params))
return """<html><head><script>
window.location = '%sredirect=' + encodeURIComponent(window.location);
window.location = '%sredirect=' + encodeURIComponent("%s");
</script></head></html>
""" % (url,)
""" % (url, redirect_url)
def load_actions_from_ir_values(key, key2, models, meta):
Values = request.session.model('ir.values')
+3 -1
View File
@@ -577,6 +577,7 @@
border-radius: 3px;
background: #f0f0fa;
color: #4C4C4C;
word-break: break-word;
}
.openerp .oe_tag_dark {
background: #7C7BAD;
@@ -620,7 +621,8 @@
width: 100% !important;
}
.openerp .oe_tags .text-core {
min-height: 22px;
height: initial !important;
word-break: break-word;
}
.openerp .oe_tags .text-core .text-wrap .text-dropdown .text-list .text-suggestion em {
font-style: italic;
+3 -1
View File
@@ -514,6 +514,7 @@ $sheet-padding: 16px
@include radius(3px)
background: $tag-bg-light
color: #4C4C4C
word-break: break-word
.oe_tag_dark
background: $tag-bg-dark
color: #eee
@@ -547,7 +548,8 @@ $sheet-padding: 16px
textarea
width: 100% !important
.text-core
min-height: 22px
height: initial !important
word-break: break-word
.text-wrap .text-dropdown .text-list .text-suggestion em
font-style: italic
text-decoration: none
+1 -1
View File
@@ -308,7 +308,7 @@ class WebsiteForum(http.Controller):
})
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), post_parent and slug(post_parent) or new_question.id))
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment', type='http', auth="public", methods=['POST'], website=True)
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment', type='http', auth="public", website=True)
def post_comment(self, forum, post, **kwargs):
if not request.session.uid:
return login_redirect()
+3 -2
View File
@@ -280,7 +280,7 @@ class website_sale(http.Controller):
}
return request.website.render("website_sale.product", values)
@http.route(['/shop/product/comment/<int:product_template_id>'], type='http', auth="public", methods=['POST'], website=True)
@http.route(['/shop/product/comment/<int:product_template_id>'], type='http', auth="public", website=True)
def product_comment(self, product_template_id, **post):
if not request.session.uid:
return login_redirect()
@@ -292,7 +292,7 @@ class website_sale(http.Controller):
type='comment',
subtype='mt_comment',
context=dict(context, mail_create_nosubscribe=True))
return werkzeug.utils.redirect(request.httprequest.referrer + "#comments")
return werkzeug.utils.redirect('/shop/product/%s#comments' % product_template_id)
@http.route(['/shop/pricelist'], type='http', auth="public", website=True)
def pricelist(self, promo, **post):
@@ -716,6 +716,7 @@ class website_sale(http.Controller):
if tx.state == 'draft': # button cliked but no more info -> rewrite on tx or create a new one ?
tx.write({
'acquirer_id': acquirer_id,
'amount': order.amount_total,
})
tx_id = tx.id
else:
+2 -1
View File
@@ -197,7 +197,8 @@ class website(orm.Model):
values.update(sale_order.onchange_pricelist_id(pricelist_id, None)['value'])
sale_order.write(values)
for line in sale_order.order_line:
sale_order._cart_update(product_id=line.product_id.id, line_id=line.id, add_qty=0)
if line.exists():
sale_order._cart_update(product_id=line.product_id.id, line_id=line.id, add_qty=0)
# update browse record
if (code and code != sale_order.pricelist_id.code) or sale_order.partner_id.id != partner.id:
@@ -124,3 +124,15 @@ class SaleOrder(orm.Model):
values['deliveries'] = DeliveryCarrier.browse(cr, SUPERUSER_ID, delivery_ids, context=delivery_ctx)
return values
def _cart_update(self, cr, uid, ids, product_id=None, line_id=None, add_qty=0, set_qty=0, context=None, **kwargs):
""" Override to update carrier quotation if quantity changed """
values = super(SaleOrder, self)._cart_update(
cr, uid, ids, product_id, line_id, add_qty, set_qty, context, **kwargs)
if add_qty or set_qty is not None:
for sale_order in self.browse(cr, uid, ids, context=context):
self._check_carrier_quotation(cr, uid, sale_order, context=context)
return values
+11
View File
@@ -0,0 +1,11 @@
Spain, 2015-04-20
I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Antonio Espinosa antespi@gmail.com https://github.com/antespi
+11
View File
@@ -0,0 +1,11 @@
Poland, 2015-06-18
I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Bartłomiej Wójcicki bartwojcicki@gmail.com https://github.com/bartekwojcicki
+11
View File
@@ -0,0 +1,11 @@
United Kingdom, 15.06.2015
I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Csaba Palankai csaba.palankai@gmail.com https://github.com/palankai
+11
View File
@@ -0,0 +1,11 @@
United Kingdom, 2015-06-18
I hereby agree to the terms of the Individual Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and
sign this declaration.
Signed,
Will Earp will.earp@icloud.com https://github.com/wearp
+2 -2
View File
@@ -621,7 +621,7 @@ instead of a single view its ``arch`` field is composed of any number of
<!-- improved idea categories list -->
<record id="idea_category_list2" model="ir.ui.view">
<field name="name">id.category.list2</field>
<field name="model">ir.ui.view</field>
<field name="model">idea.category/field>
<field name="inherit_id" ref="id_category_list"/>
<field name="arch" type="xml">
<!-- find field description inside tree, and add the field
@@ -1074,7 +1074,7 @@ predefined searches. Filters must have one of the following attributes:
domain="[('inventor_id', '=', uid)]"/>
<group string="Group By">
<filter name="group_by_inventor" string="Inventor"
context="{'group_by': 'inventor'}"/>
context="{'group_by': 'inventor_id'}"/>
</group>
</search>
+1 -1
View File
@@ -255,7 +255,7 @@ since "Carol" is not an integer, the route was ignored and no route could be
found.
Odoo provides an additional converter called ``model`` which provides records
directly when given their id, let's use that and create a generic page for
directly when given their id. Let's use this to create a generic page for
teacher biographies:
.. patch::
+4 -2
View File
@@ -18,7 +18,8 @@ new file mode 100644
--- /dev/null
+++ b/academy/views.xml
@@ -0,0 +1,13 @@
+<openerp><data>
+<openerp>
+ <data>
+ <record id="action_academy_teachers" model="ir.actions.act_window">
+ <field name="name">Academy teachers</field>
+ <field name="res_model">academy.teachers</field>
@@ -30,4 +31,5 @@ new file mode 100644
+ <menuitem id="menu_academy_content_teachers"
+ parent="menu_academy_content"
+ action="action_academy_teachers"/>
+</data></openerp>
+ </data>
+</openerp>
+2 -2
View File
@@ -230,8 +230,8 @@ Possible children elements of the list view are:
Possible attributes are ``invisible`` (hides the button) and
``readonly`` (disables the button but still shows it)
``states``
shorthand for ``invisible`` ``attrs``: a list of space, separated
states, requires that the model has a ``state`` field and that it is
shorthand for ``invisible`` ``attrs``: a list of states, comma separated,
requires that the model has a ``state`` field and that it is
used in the view.
Makes the button ``invisible`` if the record is *not* in one of the
+2 -2
View File
@@ -176,11 +176,11 @@ class Field(object):
@api.depends('name')
def _compute_upper(self):
for rec in self:
self.upper = self.name.upper() if self.name else False
rec.upper = rec.name.upper() if rec.name else False
def _inverse_upper(self):
for rec in self:
self.name = self.upper.lower() if self.upper else False
rec.name = rec.upper.lower() if rec.upper else False
def _search_upper(self, operator, value):
if operator == 'like':
+5 -4
View File
@@ -44,6 +44,7 @@ except ImportError:
import openerp
from openerp import SUPERUSER_ID
from openerp.service.server import memory_info
from openerp.service import security, model as service_model
from openerp.tools.func import lazy_property
from openerp.tools import ustr
@@ -97,7 +98,7 @@ def dispatch_rpc(service_name, method, params):
start_time = time.time()
start_rss, start_vms = 0, 0
if psutil:
start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info()
start_rss, start_vms = memory_info(psutil.Process(os.getpid()))
if rpc_request and rpc_response_flag:
openerp.netsvc.log(rpc_request, logging.DEBUG, '%s.%s' % (service_name, method), replace_request_password(params))
@@ -119,7 +120,7 @@ def dispatch_rpc(service_name, method, params):
end_time = time.time()
end_rss, end_vms = 0, 0
if psutil:
end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info()
end_rss, end_vms = memory_info(psutil.Process(os.getpid()))
logline = '%s.%s time:%.3fs mem: %sk -> %sk (diff: %sk)' % (service_name, method, end_time - start_time, start_vms / 1024, end_vms / 1024, (end_vms - start_vms)/1024)
if rpc_response_flag:
openerp.netsvc.log(rpc_response, logging.DEBUG, logline, result)
@@ -567,7 +568,7 @@ class JsonRequest(WebRequest):
start_time = time.time()
_, start_vms = 0, 0
if psutil:
_, start_vms = psutil.Process(os.getpid()).get_memory_info()
_, start_vms = memory_info(psutil.Process(os.getpid()))
if rpc_request and rpc_response_flag:
rpc_request.debug('%s: %s %s, %s',
endpoint, model, method, pprint.pformat(args))
@@ -578,7 +579,7 @@ class JsonRequest(WebRequest):
end_time = time.time()
_, end_vms = 0, 0
if psutil:
_, end_vms = psutil.Process(os.getpid()).get_memory_info()
_, end_vms = memory_info(psutil.Process(os.getpid()))
logline = '%s: %s %s: time:%.3fs mem: %sk -> %sk (diff: %sk)' % (
endpoint, model, method, end_time - start_time, start_vms / 1024, end_vms / 1024, (end_vms - start_vms)/1024)
if rpc_response_flag:
+13 -3
View File
@@ -52,6 +52,11 @@ except ImportError:
SLEEP_INTERVAL = 60 # 1 min
def memory_info(process):
""" psutil < 2.0 does not have memory_info, >= 3.0 does not have
get_memory_info """
return (getattr(process, 'memory_info', None) or process.get_memory_info)()
#----------------------------------------------------------
# Werkzeug WSGI servers patched
#----------------------------------------------------------
@@ -570,6 +575,11 @@ class PreforkServer(CommonServer):
for pid in self.workers.keys():
self.worker_kill(pid, signal.SIGINT)
while self.workers and time.time() < limit:
try:
self.process_signals()
except KeyboardInterrupt:
_logger.info("Forced shutdown.")
break
self.process_zombie()
time.sleep(0.1)
else:
@@ -650,7 +660,7 @@ class Worker(object):
_logger.info("Worker (%d) max request (%s) reached.", self.pid, self.request_count)
self.alive = False
# Reset the worker if it consumes too much memory (e.g. caused by a memory leak).
rss, vms = psutil.Process(os.getpid()).get_memory_info()
rss, vms = memory_info(psutil.Process(os.getpid()))
if vms > config['limit_memory_soft']:
_logger.info('Worker (%d) virtual memory limit (%s) reached.', self.pid, vms)
self.alive = False # Commit suicide after the request.
@@ -773,7 +783,7 @@ class WorkerCron(Worker):
self.setproctitle(db_name)
if rpc_request_flag:
start_time = time.time()
start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info()
start_rss, start_vms = memory_info(psutil.Process(os.getpid()))
import openerp.addons.base as base
base.ir.ir_cron.ir_cron._acquire_job(db_name)
@@ -784,7 +794,7 @@ class WorkerCron(Worker):
openerp.sql_db.close_db(db_name)
if rpc_request_flag:
run_time = time.time() - start_time
end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info()
end_rss, end_vms = memory_info(psutil.Process(os.getpid()))
vms_diff = (end_vms - start_vms) / 1024
logline = '%s time:%.3fs mem: %sk -> %sk (diff: %sk)' % \
(db_name, run_time, start_vms / 1024, end_vms / 1024, vms_diff)