[MERGE] forward port branch saas-13 up to 1bb51b5

This commit is contained in:
Christophe Simonis
2016-10-03 11:24:13 +02:00
38 changed files with 168 additions and 94 deletions
+2
View File
@@ -885,6 +885,8 @@ class AccountMoveLine(models.Model):
vals['date'] = self._context.get('date_p') or time.strftime('%Y-%m-%d')
if 'name' not in vals:
vals['name'] = self._context.get('comment') or _('Write-Off')
if 'analytic_account_id' not in vals:
vals['analytic_account_id'] = self.env.context.get('analytic_id', False)
#compute the writeoff amount if not given
if 'credit' not in vals and 'debit' not in vals:
amount = sum([r.amount_residual for r in self])
+2 -2
View File
@@ -7,6 +7,6 @@ from odoo import fields, models
class BaseConfigSettings(models.TransientModel):
_inherit = 'base.config.settings'
group_attendance_use_pin = fields.Selection([(0, 'Employees do not need to enter their PIN to check in manually in the "Company Screen".'),
(1, 'Employees must enter their PIN to check in manually in the "Company Screen".')],
group_attendance_use_pin = fields.Selection([(0, 'Employees do not need to enter their PIN to check in manually in the "Kiosk Mode".'),
(1, 'Employees must enter their PIN to check in manually in the "Kiosk Mode".')],
string='Employee PIN', help='Enable or disable employee PIN identification at check in', implied_group="hr_attendance.group_hr_attendance_use_pin")
+1 -1
View File
@@ -1030,7 +1030,7 @@ class MailThread(models.AbstractModel):
tools.decode_message_header(message, 'Cc'),
tools.decode_message_header(message, 'Resent-To'),
tools.decode_message_header(message, 'Resent-Cc')])
rcpt_tos_localparts = [e.split('@')[0] for e in tools.email_split(rcpt_tos)]
rcpt_tos_localparts = [e.split('@')[0].lower() for e in tools.email_split(rcpt_tos)]
# 0. Verify whether this is a bounced email and use it to collect bounce data and update notifications for customers
if bounce_alias and bounce_alias in email_to_localpart:
+4 -1
View File
@@ -230,7 +230,10 @@ class MrpProduction(models.Model):
self.bom_id = False
else:
bom = self.env['mrp.bom']._bom_find(product=self.product_id, picking_type=self.picking_type_id, company_id=self.company_id.id)
self.bom_id = bom.id
if bom.type == 'normal':
self.bom_id = bom.id
else:
self.bom_id = False
self.product_uom_id = self.product_id.uom_id.id
return {'domain': {'product_uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)]}}
+3
View File
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, exceptions, fields, models, _
from odoo.exceptions import UserError
from odoo.tools import float_compare
from odoo.addons import decimal_precision as dp
@@ -241,6 +242,8 @@ class StockMove(models.Model):
else:
for movelot in move.move_lot_ids:
if float_compare(movelot.quantity_done, 0, precision_rounding=rounding) > 0:
if not movelot.lot_id:
raise UserError(_('You need to supply a lot/serial number.'))
qty = move.product_uom._compute_quantity(movelot.quantity_done, move.product_id.uom_id)
quants = quant_obj.quants_get_preferred_domain(qty, move, lot_id=movelot.lot_id.id, domain=main_domain, preferred_domain_list=preferred_domain_list)
self.env['stock.quant'].quants_move(quants, move, move.location_dest_id, lot_id = movelot.lot_id.id)
+1 -1
View File
@@ -26,7 +26,7 @@ class MrpBomCost(models.AbstractModel):
'attributes': attributes}
total = 0.0
for bom_line, line_data in result2:
price_uom = self.env['product.uom']._compute_qty(bom_line.product_id.uom_id.id, bom_line.product_id.standard_price, bom_line.product_uom_id.id)
price_uom = bom_line.product_uom_id._compute_quantity(bom_line.product_id.standard_price, bom_line.product_uom_id)
line = {
'product_id': bom_line.product_id,
'product_uom_qty': line_data['qty'], #line_data needed for phantom bom explosion
+1 -1
View File
@@ -93,7 +93,7 @@
string="Update" states="confirmed,planned,progress" class="oe_link" attrs="{'invisible': [('state','=','done')]}"/>
</div>
<field name="bom_id"
domain="['|',
domain="['&amp;', '|',
('product_id','=',product_id),
'&amp;',
('product_tmpl_id.product_variant_ids','=',product_id),
+12 -5
View File
@@ -4,7 +4,7 @@
from odoo import api, fields, models, _
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError
import math
class ChangeProductionQty(models.TransientModel):
_name = 'change.production.qty'
@@ -43,16 +43,25 @@ class ChangeProductionQty(models.TransientModel):
if wizard.product_qty < produced:
raise UserError(_("You have already processed %d. Please input a quantity higher than %d ")%(produced, produced))
production.write({'product_qty': wizard.product_qty})
bom_point = production.bom_id
factor = self.env['product.uom']._compute_qty(production.product_uom_id.id, production.product_qty - production.qty_produced, production.bom_id.product_uom_id.id) / production.bom_id.product_qty
factor = production.product_uom_id._compute_quantity(production.product_qty - production.qty_produced, production.bom_id.product_uom_id) / production.bom_id.product_qty
boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
for line, line_data in lines:
production._update_raw_move(line, line_data)
operation_bom_qty = {}
for bom, bom_data in boms:
for operation in bom.routing_id.operation_ids:
operation_bom_qty[operation.id] = bom_data['qty']
self._update_product_to_produce(production, production.product_qty - production.qty_produced)
moves = production.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
moves.do_unreserve()
moves.action_assign()
for wo in production.workorder_ids:
operation = wo.operation_id
if operation_bom_qty.get(operation.id):
cycle_number = math.ceil(operation_bom_qty[operation.id] / operation.workcenter_id.capacity) # TODO: float_round UP
wo.duration_expected = (operation.workcenter_id.time_start +
operation.workcenter_id.time_stop +
cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency)
if production.product_id.tracking == 'serial':
quantity = 1.0
else:
@@ -62,8 +71,6 @@ class ChangeProductionQty(models.TransientModel):
if wo.qty_produced < wo.qty_production and wo.state == 'done':
wo.state = 'progress'
# assign moves; last operation receive all unassigned moves
operation = wo.operation_id
# TODO: following could be put in a function as it is similar as code in _workorders_create
# TODO: only needed when creating new moves
moves_raw = production.move_raw_ids.filtered(lambda move: move.operation_id == operation and move.state not in ('done', 'cancel'))
@@ -23,6 +23,7 @@ class MrpProduction(models.Model):
'product_uom': sub_product.product_uom_id.id,
'location_id': source,
'location_dest_id': production.location_dest_id.id,
'operation_id': sub_product.operation_id.id,
'production_id': production.id,
'origin': production.name,
'unit_factor': qty1 / (production.product_qty - production.qty_produced),
@@ -13,9 +13,9 @@ class ChangeProductionQty(models.TransientModel):
Production = self.env['mrp.production']
UoM = self.env['product.uom']
for sub_product_line in prod.bom_id.sub_products:
move = prod.move_finished_ids.filtered(lambda x: x.sub_product_id == sub_product_line and x.state not in ('done', 'cancel'))
move = prod.move_finished_ids.filtered(lambda x: x.subproduct_id == sub_product_line and x.state not in ('done', 'cancel'))
if move:
product_uom_factor = UoM._compute_qty_obj(prod.product_uom_id, prod.product_qty - prod.qty_produced, prod.bom_id.product_uom_id)
product_uom_factor = prod.product_uom_id._compute_quantity(prod.product_qty - prod.qty_produced, prod.bom_id.product_uom_id)
qty1 = sub_product_line.product_qty
qty1 *= product_uom_factor / prod.bom_id.product_qty
move[0].write({'product_uom_qty': qty1})
@@ -80,9 +80,11 @@
</t>
</template>
<template id="pay_meth_link" inherit_id="website_portal.portal_layout">
<template id="pay_meth_link" inherit_id="website_portal.portal_layout" customize_show="True">
<xpath expr="//div[@class='o_my_details']" position="inside">
<div class='manage_payment_method mt16'><a href="/my/payment_method">Manage your payment methods</a></div>
<t t-if="request.env['payment.acquirer'].search([('website_published', '=', True), ('registration_view_template_id', '!=', False)])">
<div class='manage_payment_method mt16'><a href="/my/payment_method">Manage your payment methods</a></div>
</t>
</xpath>
</template>
+5
View File
@@ -902,6 +902,11 @@ class WebsiteSale(http.Controller):
return request.redirect('/shop/confirmation')
@http.route(['/shop/terms'], type='http', auth="public", website=True)
def terms(self, **kw):
return request.render("website_sale.terms")
@http.route(['/shop/confirmation'], type='http', auth="public", website=True)
def payment_confirmation(self, **post):
""" End of checkout process controller. Confirmation is basically seing
@@ -630,4 +630,8 @@ a.no-decoration {
opacity: 1;
}
.ecom-zoomable img[data-zoom] {
cursor: zoom-in;
}
/*# sourceMappingURL=website_sale.css.map */
@@ -539,3 +539,6 @@ a.no-decoration
&.active img
opacity: 1
.ecom-zoomable img[data-zoom]
cursor: zoom-in
+123 -79
View File
@@ -788,7 +788,9 @@
</div>
<div class="form-group">
<div class="col-md-offset-3 col-sm-offset-4 col-sm-8 col-md-7">
<span class="btn btn-primary btn-lg o_website_form_send o_default_snippet_text">Send</span>
<span class="btn btn-primary pull-right btn-lg o_website_form_send o_default_snippet_text">
<span>Next </span><span class="fa fa-long-arrow-right" />
</span>
<span id="o_website_form_result" class="text-danger ml8" />
</div>
</div>
@@ -886,8 +888,10 @@
</t>
</tbody>
</table>
<div class="js_cart_lines pull-right">
<t t-call="website_sale.total" />
<div class="js_cart_lines row">
<t t-call="website_sale.total">
<t t-set='extra_class' t-value='"col-sm-4 col-sm-offset-8 col-xs-12"'/>
</t>
</div>
</template>
@@ -1268,7 +1272,7 @@
</div>
</t>
</template>
<template id="payment">
<template id="payment" name="Payment">
<t t-call="website.layout">
<t t-set="additional_title">Shop - Select Payment Method</t>
<div id="wrap">
@@ -1325,11 +1329,76 @@
</tr>
</tbody>
</table>
<div class="pull-right">
<t t-call="website_sale.total" />
<div>
<t t-call="website_sale.total">
<t t-set='extra_class' t-value='"col-sm-4 col-sm-offset-8 col-xs-12"'/>
</t>
</div>
<div class="clearfix" />
<div class="oe_structure" />
<div class="js_payment mb64 row" t-if="acquirers and website_sale_order.amount_total" id="payment_method">
<div class="col-lg-5 col-sm-6">
<h4>Payment Method:</h4>
<ul class="list-unstyled">
<t t-foreach="acquirers or []" t-as="acquirer">
<li>
<label t-if="acquirer.button">
<input t-att-value="acquirer.id" type="radio" name="acquirer" t-att-checked="acquirers[0] == acquirer" />
<span t-field="acquirer.image_small" t-att-title="acquirer.name" t-field-options='{"widget": "image", "style":"max-width: 60px; display: inline-block"}'/>
<span t-field="acquirer.name" />
<span t-if="acquirer.fees_active">(processing fees apply)</span>
</label>
</li>
</t>
<li t-if="tokens">
<label>
<input type="radio" name="acquirer" />
<span class='fa fa-2x fa-credit-card'/>
Saved Cards
</label>
<div class="list-group">
<t t-foreach='tokens' t-as='token'>
<a class="list-group-item btn_payment_token" t-att-data-acquirer="token.acquirer_id.id" t-att-data-token='token.id'>
<span class="js_radio fa fa-circle-o"></span>&amp;nbsp;
<t t-esc="token.name" />
<t t-if="len(set(tokens.mapped('acquirer_id')))>1">
(<t t-esc='token.acquirer_id.name'/>)
</t>
<span t-if="token.acquirer_id.fees_active">(processing fees apply)</span>
</a>
</t>
</div>
</li>
</ul>
</div>
<div class="col-lg-5 col-lg-offset-2 col-sm-6 text-right">
<t t-foreach="acquirers or []" t-as="acquirer" id="acquirers_list">
<div t-att-data-id="acquirer.id" class="oe_sale_acquirer_button hidden pull-right">
<div t-raw="acquirer.button" />
<div class="token_hide">
<div t-if="acquirer.save_token == 'ask'">
<input type="checkbox" name="odoo_save_token"/>
<label for="odoo_save_token">Save my payment data</label>
</div>
<div class="pre_msg" t-field="acquirer.pre_msg" />
</div>
</div>
</t>
</div>
</div>
<div class="js_payment mb64 row" t-if="not website_sale_order.amount_total" id="payment_method">
<div class="col-sm-12">
<form target="_self" action="/shop/payment/validate" method="post" class="pull-right">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<a style="width:127px;" class="btn btn-primary a-submit">
<span t-if="order.amount_total &gt; 0">Pay Now <span class="fa fa-long-arrow-right"></span></span>
<span t-if="order.amount_total == 0">Confirm Order <span class="fa fa-long-arrow-right"></span></span>
</a>
</form>
</div>
</div>
</div>
<div class="col-lg-3 col-lg-offset-1 col-sm-3 text-muted" id="right_column">
<t t-call='website_sale.bill_to'>
@@ -1337,85 +1406,21 @@
</t>
</div>
</div>
<div class="js_payment mb64 row" t-if="acquirers and website_sale_order.amount_total" id="payment_method">
<div class="col-lg-5 col-sm-6">
<h4>Payment Method:</h4>
<ul class="list-unstyled">
<t t-foreach="acquirers or []" t-as="acquirer">
<li>
<label t-if="acquirer.button">
<input t-att-value="acquirer.id" type="radio" name="acquirer" t-att-checked="acquirers[0] == acquirer" />
<span t-field="acquirer.image_small" t-att-title="acquirer.name" t-field-options='{"widget": "image", "style":"max-width: 60px; display: inline-block"}'/>
<span t-field="acquirer.name" />
<span t-if="acquirer.fees_active">(processing fees apply)</span>
</label>
</li>
</t>
<li t-if="tokens">
<label>
<input type="radio" name="acquirer" />
<span class='fa fa-2x fa-credit-card'/>
Saved Cards
</label>
<div class="list-group">
<t t-foreach='tokens' t-as='token'>
<a class="list-group-item btn_payment_token" t-att-data-acquirer="token.acquirer_id.id" t-att-data-token='token.id'>
<span class="js_radio fa fa-circle-o"></span>&amp;nbsp;
<t t-esc="token.name" />
<t t-if="len(set(tokens.mapped('acquirer_id')))>1">
(<t t-esc='token.acquirer_id.name'/>)
</t>
<span t-if="token.acquirer_id.fees_active">(processing fees apply)</span>
</a>
</t>
</div>
</li>
</ul>
</div>
<div class="col-lg-3 col-sm-3">
<t t-foreach="acquirers or []" t-as="acquirer" id="acquirers_list">
<div t-att-data-id="acquirer.id" class="oe_sale_acquirer_button hidden pull-right">
<div t-raw="acquirer.button" />
<div class="token_hide">
<div t-if="acquirer.save_token == 'ask'">
<input type="checkbox" name="odoo_save_token"/>
<label for="odoo_save_token">Save my payment data</label>
</div>
<div class="pre_msg" t-field="acquirer.pre_msg" />
</div>
</div>
</t>
</div>
</div>
<div class="js_payment mb64 row" t-if="not website_sale_order.amount_total" id="payment_method">
<div class="col-lg-8 col-sm-8">
<form target="_self" action="/shop/payment/validate" method="post" class="pull-right">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<a style="width:127px;" class="btn btn-primary a-submit">
<span t-if="order.amount_total &gt; 0">Pay Now <span class="fa fa-long-arrow-right"></span></span>
<span t-if="order.amount_total == 0">Confirm Order <span class="fa fa-long-arrow-right"></span></span>
</a>
</form>
</div>
</div>
</div>
<div class="oe_structure" />
</div>
</t>
</template>
<template id="payment_sale_note" inherit_id="payment" name="Display Sale Note" customize_show="True" active="False">
<template id="payment_sale_note" inherit_id="payment" name="Accept Terms &amp; Conditions" customize_show="True" active="False">
<xpath expr="//t[@id='acquirers_list']" position="before">
<t t-set="sale_note" t-value="website_sale_order.note" />
<t t-if="sale_note and sale_note != ''">
<div class="oe_accept_cgv_button">
<label>
<input type="checkbox" checked="checked" id="checkbox_cgv" />
<t t-esc="sale_note" />
</label>
</div>
</t>
<div class="oe_accept_cgv_button">
<label>
<input type="checkbox" checked="checked" id="checkbox_cgv" />
I agree to the <a target='_BLANK' href='/shop/terms'>terms &amp; conditions</a>
</label>
</div>
</xpath>
</template>
@@ -1578,7 +1583,7 @@
</template>
<template id="total">
<div id="cart_total" t-if="website_sale_order">
<div id="cart_total" t-att-class="extra_class or ''" t-if="website_sale_order">
<div class="row" id="order_total_untaxed">
<span class="col-xs-6 text-right text-muted">Subtotal:</span>
<span class="col-xs-6 text-left text-muted">
@@ -1750,4 +1755,43 @@
</t>
</xpath>
</template>
<template id="terms" name="Terms &amp; Conditions">
<t t-call="website.layout">
<div id="wrap">
<div class="oe_structure">
<section class="s_title">
<div class="container">
<div class="row">
<div class="col-md-12">
<h1 class="text-center">Terms &amp;amp; Conditions</h1>
<div class="well s_well clearfix">
<ul>
<li>The <b>Intellectual Property</b> disclosure will inform users that the contents, logo and other visual media you created is your property and is protected by copyright laws.</li>
<li>A <b>Termination</b> clause will inform that users’ accounts on your website and mobile app or users’ access to your website and mobile (if users can’t have an account with you) can be terminated in case of abuses or at your sole discretion.</li>
<li>A <b>Governing Law</b> will inform users which laws govern the agreement. This should the country in which your company is headquartered or the country from which you operate your web site and mobile app.</li>
<li>A <b>Links To Other Web Sites</b> clause will inform users that you are not responsible for any third party web sites that you link to. This kind of clause will generally inform users that they are responsible for reading and agreeing (or disagreeing) with the Terms and Conditions or Privacy Policies of these third parties.</li>
<li>If your website or mobile apps allows users to create content and make that content public to other users, a <b>Content</b> section will inform users that they own the rights to the content they have created.<br/>The “Content” clause usually mentions that users must give you (the website or mobile app developer) a license so that you can share this content on your website/mobile app and to make it available to other users.<br/>Because the content created by users is public to other users, a DMCA notice clause (or Copyright Infringement ) section is helpful to inform users and copyright authors that, if any content is found to be a copyright infringement, you will respond to any DMCA take down notices received and you will take down the content.</li>
<li>A <b>Limit What Users Can Do</b> clause can inform users that by agreeing to use your service, they’re also agreeing to not do certain things. This can be part of a very long and thorough list in your Terms and Conditions agreements so as to encompass the most amount of negative uses.</li>
</ul>
<small class="text-muted pull-right">Source: https://termsfeed.com/blog/sample-terms-and-conditions-template</small>
</div>
</div>
</div>
</div>
</section>
<section class="s_text_block">
<div class="container">
<div class="row">
<div class="col-md-12 mb16 mt16">
<p style='white-space:pre' t-esc="website.company_id.sale_note"/>
</div>
</div>
</div>
</section>
</div>
<div class="oe_structure"/>
</div>
</t>
</template>
</odoo>