account_id = repair.partner_id.property_account_receivable.id
inv = {
'name': repair.name,
- 'origin':repair.name,
+ 'origin': repair.name,
'type': 'out_invoice',
'account_id': account_id,
- 'partner_id': repair.partner_id.id,
+ 'partner_id': repair.partner_invoice_id.id or repair.partner_id.id,
'currency_id': repair.pricelist_id.currency_id.id,
'comment': repair.quotation_notes,
'fiscal_position': repair.partner_id.property_account_position.id
</field>
</record>
- <record id="product_normal_action" model="ir.actions.act_window">
+ <record id="product_template_action" model="ir.actions.act_window">
<field name="name">Products</field>
<field name="type">ir.actions.act_window</field>
- <field name="res_model">product.product</field>
+ <field name="res_model">product.template</field>
+ <field name="view_mode">kanban,tree,form</field>
<field name="view_type">form</field>
- <field name="view_mode">tree,form,kanban</field>
- <field name="view_id" ref="product_product_tree_view"/>
- <field name="search_view_id" ref="product_search_form_view"/>
- <field name="help" type="html">
- <p class="oe_view_nocontent_create">
- Click to define a new product.
- </p><p>
- You must define a product for everything you buy or sell,
- whether it's a physical product, a consumable or service.
- </p>
+ <field name="view_id" ref="product_template_kanban_view"/>
++ <field name="context">{"search_default_filter_to_sell":1}</field>
+ </record>
+
+ <menuitem action="product_template_action"
+ id="menu_product_template_action"
+ parent="base.menu_product" sequence="1" />
+
+ <!-- product product -->
+
+ <menuitem id="prod_config_main" name="Product Variants" parent="base.menu_base_config" sequence="70" groups="base.group_no_one"/>
+
+ <record id="product_product_tree_view" model="ir.ui.view">
+ <field name="name">product.product.tree</field>
+ <field name="model">product.product</field>
+ <field eval="7" name="priority"/>
+ <field name="arch" type="xml">
+
+ <tree string="Product Variants">
+ <field name="default_code"/>
+ <field name="name"/>
+ <field name="attribute_value_ids" widget="many2many_tags"/>
+ <field name="lst_price"/>
+ <field name="price" invisible="not context.get('pricelist',False)"/>
+ <field name="uom_id"/>
+ <field name="ean13"/>
+ <field name="state" invisible="1"/>
+ <field name="product_tmpl_id" invisible="1"/>
+ </tree>
+
+ </field>
+ </record>
+
+ <record id="product_normal_form_view" model="ir.ui.view">
+ <field name="name">product.product.form</field>
+ <field name="model">product.product</field>
+ <field name="mode">primary</field>
+ <field eval="7" name="priority"/>
+ <field name="inherit_id" ref="product.product_template_form_view"/>
+ <field name="arch" type="xml">
+ <form position="attributes">
+ <attribute name="string">Product Variant</attribute>
+ </form>
+ <field name="list_price" position="attributes">
+ <attribute name="name">lst_price</attribute>
+ </field>
+ <field name="name" position="replace">
+ <field name="name" attrs="{'invisible': [('id', '!=', False)]}"/>
+ <field name="product_tmpl_id" class="oe_inline" readonly="1" attrs="{'invisible': [('id', '=', False)], 'required': [('id', '!=', False)]}"/>
+ </field>
+ <xpath expr="//div[@class='oe_title']" position="inside">
+ <field name="attribute_value_ids" widget="many2many_tags"/>
+ </xpath>
</field>
</record>
+
+ <record id="product_kanban_view" model="ir.ui.view">
+ <field name="name">Product Kanban</field>
+ <field name="model">product.product</field>
+ <field name="mode">primary</field>
+ <field name="inherit_id" ref="product.product_template_kanban_view"/>
+ <field name="arch" type="xml">
+ <field name="name" position="after">
+ <field name="attribute_value_ids"/>
+ </field>
+ <xpath expr="//img[@class='oe_kanban_image']" position="replace">
+ <img t-att-src="kanban_image('product.product', 'image_small', record.id.value)" class="oe_kanban_image"/>
+ </xpath>
+ </field>
+ </record>
+
+ <!-- -->
+
<record id="product_normal_action_sell" model="ir.actions.act_window">
- <field name="name">Products</field>
+ <field name="name">Product Variants</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">product.product</field>
<field name="view_mode">kanban,tree,form</field>
<field name="name"/>
<field name="picking_id" string="Reference"/>
<field name="origin"/>
- <field name="type" on_change="onchange_move_type(type)"/>
+ <field name="picking_type_id"/>
<field name="create_date" invisible="1" groups="base.group_no_one"/>
<field name="product_id" on_change="onchange_product_id(product_id,location_id,location_dest_id, False)"/>
- <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos)"/>
+ <field name="product_uom_qty" on_change="onchange_quantity(product_id, product_uom_qty, product_uom, product_uos)"/>
<field name="product_uom" string="Unit of Measure" groups="product.group_uom"/>
+ <field name="product_uos_qty" groups="product.group_uos"/>
<field name="product_uos" groups="product.group_uos"/>
<button name="%(stock.move_scrap)d"
string="Scrap Products" type="action"
<field name="arch" type="xml">
<tree colors="grey:scrapped == True" string="Stock Moves">
<field name="product_id"/>
- <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos)"/>
+ <field name="product_uom_qty" on_change="onchange_quantity(product_id, product_uom_qty, product_uom, product_uos)"/>
<field name="product_uom" string="Unit of Measure" groups="product.group_uom"/>
+ <field name="product_uos_qty" groups="product.group_uos"/>
<field name="product_uos" groups="product.group_uos"/>
<field name="location_id" groups="stock.group_locations" invisible="1"/>
<field name="picking_id" invisible="1" />
url_redirect += '?' + r.query_string
response = werkzeug.utils.redirect(url_redirect, 302)
request.session.db = db
- response = r.app.get_response(r, response, explicit_session=False)
- werkzeug.exceptions.abort(response)
- return
+ abort_and_redirect(url_redirect)
# if db not provided, use the session one
- if not db:
+ if not db and http.db_filter([request.session.db]):
db = request.session.db
# if no database provided and no database in session, use monodb
@http.route('/login', type='http', auth="none")
def login(self, db, login, key, redirect="/web", **kw):
+ if not http.db_filter([db]):
+ return werkzeug.utils.redirect('/', 303)
return login_and_redirect(db, login, key, redirect_url=redirect)
-class WebClient(http.Controller):
-
- @http.route('/web/webclient/csslist', type='json', auth="none")
- def csslist(self, mods=None):
- return manifest_list('css', mods=mods)
-
- @http.route('/web/webclient/jslist', type='json', auth="none")
- def jslist(self, mods=None):
- return manifest_list('js', mods=mods)
-
- @http.route('/web/webclient/qweblist', type='json', auth="none")
- def qweblist(self, mods=None):
- return manifest_list('qweb', mods=mods)
-
- @http.route('/web/webclient/css', type='http', auth="none")
- def css(self, mods=None, db=None):
- files = list(manifest_glob('css', addons=mods, db=db))
- last_modified = get_last_modified(f[0] for f in files)
- if request.httprequest.if_modified_since and request.httprequest.if_modified_since >= last_modified:
- return werkzeug.wrappers.Response(status=304)
-
- file_map = dict(files)
-
- rx_import = re.compile(r"""@import\s+('|")(?!'|"|/|https?://)""", re.U)
- rx_url = re.compile(r"""url\s*\(\s*('|"|)(?!'|"|/|https?://|data:)""", re.U)
-
- def reader(f):
- """read the a css file and absolutify all relative uris"""
- with open(f, 'rb') as fp:
- data = fp.read().decode('utf-8')
-
- path = file_map[f]
- web_dir = os.path.dirname(path)
-
- data = re.sub(
- rx_import,
- r"""@import \1%s/""" % (web_dir,),
- data,
- )
-
- data = re.sub(
- rx_url,
- r"url(\1%s/" % (web_dir,),
- data,
- )
- return data.encode('utf-8')
+ @http.route('/web/js/<xmlid>', type='http', auth="public")
+ def js_bundle(self, xmlid, **kw):
+ # manifest backward compatible mode, to be removed
+ values = {'manifest_list': manifest_list}
+ try:
+ assets_html = request.render(xmlid, lazy=False, qcontext=values)
+ except QWebTemplateNotFound:
+ return request.not_found()
+ bundle = AssetsBundle(xmlid, assets_html, debug=request.debug)
- content, checksum = concat_files((f[0] for f in files), reader)
+ response = request.make_response(
+ bundle.js(), [('Content-Type', 'application/javascript')])
- # move up all @import and @charset rules to the top
- matches = []
- def push(matchobj):
- matches.append(matchobj.group(0))
- return ''
+ # TODO: check that we don't do weird lazy overriding of __call__ which break body-removal
+ return make_conditional(
+ response, bundle.last_modified, bundle.checksum, max_age=60*60*24)
- content = re.sub(re.compile("(@charset.+;$)", re.M), push, content)
- content = re.sub(re.compile("(@import.+;$)", re.M), push, content)
+ @http.route('/web/css/<xmlid>', type='http', auth='public')
+ def css_bundle(self, xmlid, **kw):
+ values = {'manifest_list': manifest_list} # manifest backward compatible mode, to be removed
+ try:
+ assets_html = request.render(xmlid, lazy=False, qcontext=values)
+ except QWebTemplateNotFound:
+ return request.not_found()
+ bundle = AssetsBundle(xmlid, assets_html, debug=request.debug)
- matches.append(content)
- content = '\n'.join(matches)
+ response = request.make_response(
+ bundle.css(), [('Content-Type', 'text/css')])
return make_conditional(
- request.make_response(content, [('Content-Type', 'text/css')]),
- last_modified, checksum)
+ response, bundle.last_modified, bundle.checksum, max_age=60*60*24)
- @http.route('/web/webclient/js', type='http', auth="none")
- def js(self, mods=None, db=None):
- files = [f[0] for f in manifest_glob('js', addons=mods, db=db)]
- last_modified = get_last_modified(files)
- if request.httprequest.if_modified_since and request.httprequest.if_modified_since >= last_modified:
- return werkzeug.wrappers.Response(status=304)
+class WebClient(http.Controller):
- content, checksum = concat_js(files)
+ @http.route('/web/webclient/csslist', type='json', auth="none")
+ def csslist(self, mods=None):
+ return manifest_list('css', mods=mods)
- return make_conditional(
- request.make_response(content, [('Content-Type', 'application/javascript')]),
- last_modified, checksum)
+ @http.route('/web/webclient/jslist', type='json', auth="none")
+ def jslist(self, mods=None):
+ return manifest_list('js', mods=mods)
@http.route('/web/webclient/qweb', type='http', auth="none")
def qweb(self, mods=None, db=None):
.openerp .oe_application .oe_form_sheet .oe_notebook_page {
padding: 0 16px;
}
- .openerp .oe_form > :not(.oe_form_nosheet) header {
+ .openerp .oe_form > :not(.oe_form_nosheet) header, .openerp .oe_form > .oe_form_nosheet header {
padding-left: 2px;
}
- .openerp .oe_form > :not(.oe_form_nosheet) header ul:not(.oe_tooltip_technical):not(.oe_dropdown_menu) {
-.openerp .oe_form > :not(.oe_form_nosheet) header ul, .openerp .oe_form > .oe_form_nosheet header ul {
++.openerp .oe_form > :not(.oe_form_nosheet) header ul:not(.oe_tooltip_technical):not(.oe_dropdown_menu), .openerp .oe_form > .oe_form_nosheet header ul:not(.oe_tooltip_technical):not(.oe_dropdown_menu) {
display: inline-block;
float: right;
}
padding: 0 16px
// }}}
// FormView.header {{{
- .oe_form > :not(.oe_form_nosheet) header
+ .oe_form > :not(.oe_form_nosheet) header, .oe_form > .oe_form_nosheet header
padding-left: 2px
- ul
+ ul:not(.oe_tooltip_technical):not(.oe_dropdown_menu)
display: inline-block
float: right
.oe_button
class website_event(website_event):
- @http.route(['/event/add_cart'], type='http', auth="public", website=True, multilang=True)
- def add_cart(self, event_id, **post):
- user_obj = request.registry['res.users']
- order_line_obj = request.registry.get('sale.order.line')
- ticket_obj = request.registry.get('event.event.ticket')
- order_obj = request.registry.get('sale.order')
- website = request.registry['website']
-
- order = website.ecommerce_get_current_order(request.cr, request.uid, context=request.context)
- if not order:
- order = website.ecommerce_get_new_order(request.cr, request.uid, context=request.context)
-
- partner_id = user_obj.browse(request.cr, SUPERUSER_ID, request.uid,
- context=request.context).partner_id.id
- fields = [k for k, v in order_line_obj._columns.items()]
- values = order_line_obj.default_get(request.cr, SUPERUSER_ID, fields,
- context=request.context)
+ @http.route(['/event/cart/update'], type='http', auth="public", methods=['POST'], website=True)
+ def cart_update(self, event_id, **post):
+ cr, uid, context = request.cr, request.uid, request.context
+ ticket_obj = request.registry.get('event.event.ticket')
- _values = None
+ sale = False
for key, value in post.items():
- try:
- quantity = int(value)
- assert quantity > 0
- except:
- quantity = None
- ticket_id = key.split("-")[0] == 'ticket' and int(key.split("-")[1]) or None
- if not ticket_id or not quantity:
+ quantity = int(value or "0")
+ if not quantity:
continue
- ticket = ticket_obj.browse(request.cr, request.uid, ticket_id,
- context=request.context)
-
- values['product_id'] = ticket.product_id.id
- values['event_id'] = ticket.event_id.id
- values['event_ticket_id'] = ticket.id
- values['product_uom_qty'] = quantity
- values['price_unit'] = ticket.price
- values['order_id'] = order.id
- values['name'] = "%s: %s" % (ticket.event_id.name, ticket.name)
-
- # change and record value
- pricelist_id = order.pricelist_id and order.pricelist_id.id or False
- _values = order_line_obj.product_id_change(
- request.cr, SUPERUSER_ID, [], pricelist_id, ticket.product_id.id,
- partner_id=partner_id, context=request.context)['value']
+ sale = True
+ ticket_id = key.split("-")[0] == 'ticket' and int(key.split("-")[1]) or None
+ ticket = ticket_obj.browse(cr, SUPERUSER_ID, ticket_id, context=context)
+ request.website.sale_get_order(force_create=1)._cart_update(
+ product_id=ticket.product_id.id, add_qty=quantity, context=dict(context, event_ticket_id=ticket.id))
+ if 'tax_id' in _values:
+ _values['tax_id'] = [(6, 0, _values['tax_id'])]
- _values.update(values)
-
- order_line_id = order_line_obj.create(request.cr, SUPERUSER_ID, _values, context=request.context)
- order_obj.write(request.cr, SUPERUSER_ID, [order.id], {'order_line': [(4, order_line_id)]}, context=request.context)
- if not _values:
- return request.redirect("/event/%s/" % event_id)
+ if not sale:
+ return request.redirect("/event/%s" % event_id)
return request.redirect("/shop/checkout")
def _add_event(self, event_name="New Event", context={}, **kwargs):