[MERGE] forward port branch saas-15 up to 4d4d75709d

This commit is contained in:
Christophe Simonis
2017-09-04 18:12:00 +02:00
14 changed files with 66 additions and 39 deletions
+1 -1
View File
@@ -928,7 +928,7 @@ class Lead(models.Model):
result['activity']['today'] += 1
if date.today() <= date_deadline <= date.today() + timedelta(days=7):
result['activity']['next_7_days'] += 1
if date_deadline < date.today():
if date_deadline < date.today() and not opp.date_closed:
result['activity']['overdue'] += 1
# Won in Opportunities
if opp.date_closed and opp.stage_id.probability == 100:
+1 -1
View File
@@ -68,7 +68,7 @@ class HrAttendance(models.Model):
('check_in', '<=', attendance.check_in),
('id', '!=', attendance.id),
], order='check_in desc', limit=1)
if last_attendance_before_check_in and last_attendance_before_check_in.check_out and last_attendance_before_check_in.check_out >= attendance.check_in:
if last_attendance_before_check_in and last_attendance_before_check_in.check_out and last_attendance_before_check_in.check_out > attendance.check_in:
raise exceptions.ValidationError(_("Cannot create new attendance record for %(empl_name)s, the employee was already checked in on %(datetime)s") % {
'empl_name': attendance.employee_id.name,
'datetime': fields.Datetime.to_string(fields.Datetime.context_timestamp(self, fields.Datetime.from_string(attendance.check_in))),
+9 -2
View File
@@ -299,6 +299,13 @@ class HrExpense(models.Model):
})
return account_move
@api.multi
def unlink(self):
for expense in self:
if expense.state in ['done']:
raise UserError(_('You cannot delete a posted expense.'))
super(HrExpense, self).unlink()
@api.multi
def action_get_attachment_view(self):
self.ensure_one()
@@ -441,8 +448,8 @@ class HrExpenseSheet(models.Model):
@api.multi
def unlink(self):
for expense in self:
if expense.state == "post":
raise UserError(_("You cannot delete a posted expense."))
if expense.state in ['post', 'done']:
raise UserError(_('You cannot delete a posted or paid expense.'))
super(HrExpenseSheet, self).unlink()
@api.multi
-20
View File
@@ -26,26 +26,6 @@
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
<record id="hr_expense_report_prevent_unlink" model="ir.rule">
<field name="name">Expense Report Prevent Delete Employee</field>
<field name="model_id" ref="model_hr_expense_sheet"/>
<field name="domain_force">[('state', '=', 'submit')]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="True"/>
</record>
<record id="hr_expense_report_auth_unlink" model="ir.rule">
<field name="name">Expense Report Authorize Delete Officer</field>
<field name="model_id" ref="model_hr_expense_sheet"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('hr_expense.group_hr_expense_user'))]"/>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="True"/>
</record>
</data>
</odoo>
@@ -0,0 +1,7 @@
from openerp.modules.registry import RegistryManager
def migrate(cr, version):
registry = RegistryManager.get(cr.dbname)
from openerp.addons.account.models.chart_template import migrate_tags_on_taxes
migrate_tags_on_taxes(cr, registry)
@@ -0,0 +1,7 @@
from openerp.modules.registry import RegistryManager
def migrate(cr, version):
registry = RegistryManager.get(cr.dbname)
from openerp.addons.account.models.chart_template import migrate_set_tags_and_taxes_updatable
migrate_set_tags_and_taxes_updatable(cr, registry, 'l10n_fr')
+1
View File
@@ -340,6 +340,7 @@ class MrpProduction(models.Model):
source_location = self.location_src_id
original_quantity = self.product_qty - self.qty_produced
data = {
'sequence': bom_line.sequence,
'name': self.name,
'date': self.date_planned_start,
'date_expected': self.date_planned_start,
@@ -34,6 +34,9 @@ class PackOperation(models.Model):
product_qty = fields.Float('To Do', default=0.0, digits=dp.get_precision('Product Unit of Measure'), required=True)
ordered_qty = fields.Float('Ordered Quantity', digits=dp.get_precision('Product Unit of Measure'))
qty_done = fields.Float('Done', default=0.0, digits=dp.get_precision('Product Unit of Measure'))
qty_done_uom_ordered = fields.Float(
'Quantity Done', digits=dp.get_precision('Product Unit of Measure'), compute='_compute_qty_done_uom_ordered',
help='Quantity done in UOM ordered')
is_done = fields.Boolean(compute='_compute_is_done', string='Done', readonly=False, oldname='processed_boolean')
package_id = fields.Many2one('stock.quant.package', 'Source Package')
pack_lot_ids = fields.One2many('stock.pack.operation.lot', 'operation_id', 'Lots/Serial Numbers Used')
@@ -126,6 +129,14 @@ class PackOperation(models.Model):
else:
self.lots_visible = self.product_id.tracking != 'none'
@api.multi
def _compute_qty_done_uom_ordered(self):
for pack in self:
if pack.product_uom_id and pack.linked_move_operation_ids:
pack.qty_done_uom_ordered = pack.product_uom_id._compute_quantity(pack.qty_done, pack.linked_move_operation_ids[0].move_id.product_uom)
else:
pack.qty_done_uom_ordered = pack.qty_done
@api.onchange('pack_lot_ids')
def _onchange_packlots(self):
self.qty_done = sum([x.qty for x in self.pack_lot_ids])
+8 -3
View File
@@ -125,11 +125,16 @@
</t>
</td>
<td class="text-right" t-if="pack_operation.state == 'done'">
<t t-if="pack_operation.ordered_qty != pack_operation.qty_done">
<t t-if="pack_operation.ordered_qty != pack_operation.qty_done_uom_ordered">
<t t-set="backorder" t-value="True"/>
</t>
<span t-field="pack_operation.qty_done"/>
<span t-field="pack_operation.product_uom_id"/>
<span t-field="pack_operation.qty_done_uom_ordered"/>
<t t-if="pack_operation.linked_move_operation_ids">
<span t-field="pack_operation.linked_move_operation_ids[0].move_id.product_uom"></span>
</t>
<t t-else="1">
<span t-field="pack_operation.product_uom_id"></span>
</t>
</td>
</tr>
</tbody>
+5 -5
View File
@@ -201,7 +201,7 @@
</tbody>
</table>
<t t-if="not bins">
<div class="text-center text-muted">
<div class="text-center text-muted oe_product">
<h3 class="css_editable_display">No product defined.</h3>
<p groups="sales_team.group_sale_manager">Click <i>'New'</i> in the top-right corner to create your first product.</p>
</div>
@@ -413,8 +413,8 @@
<div id="o-carousel-product" class="carousel slide" data-ride="carousel" data-interval="0">
<div class="carousel-outer">
<div class="carousel-inner">
<div class="item active" itemprop="image" t-field="product.product_variant_id.image" t-options="{'widget': 'image', 'class': 'product_detail_img js_variant_img', 'alt-field': 'name', 'zoom': 'image', 'unique': product['__last_update'] + product.product_variant_id['__last_update']}"/>
<div t-if="variant_img" class="item" itemprop="image" t-field="product.image" t-options="{'widget': 'image', 'class': 'product_detail_img', 'alt-field': 'name', 'zoom': 'image', 'unique': product['__last_update'] + product.product_variant_id['__last_update']}"/>
<div class="item active" itemprop="image" t-field="product.image" t-options="{'widget': 'image', 'class': 'product_detail_img js_variant_img', 'alt-field': 'name', 'zoom': 'image', 'unique': product['__last_update']}"/>
<div t-if="variant_img" class="item" itemprop="image" t-field="product.product_variant_id.image" t-options="{'widget': 'image', 'class': 'product_detail_img', 'alt-field': 'name', 'zoom': 'image', 'unique': product['__last_update'] + (product.product_variant_id['__last_update'] or '')}"/>
<t t-if="len(image_ids)" t-foreach="image_ids" t-as="pimg">
<div class="item" t-field="pimg.image" t-options='{"widget": "image", "class": "product_detail_img", "alt-field": "name", "zoom": "image" }'/>
</t>
@@ -434,10 +434,10 @@
<ol class="carousel-indicators" t-if="len(image_ids) or variant_img">
<li data-target="#o-carousel-product" data-slide-to="0" class="active">
<img class="img img-responsive js_variant_img_small" t-attf-src="/website/image/product.product/{{product.product_variant_ids[0].id}}/image/90x90" t-att-alt="product.name"/>
<img class="img img-responsive js_variant_img_small" t-attf-src="/website/image/product.template/{{product.id}}/image/90x90" t-att-alt="product.name"/>
</li>
<li t-if="variant_img" data-target="#o-carousel-product" data-slide-to="1" class="">
<img class="img img-responsive" t-attf-src="/website/image/product.template/{{product.id}}/image/90x90" t-att-alt="product.name"/>
<img class="img img-responsive" t-attf-src="/website/image/product.product/{{product.product_variant_id.id}}/image/90x90" t-att-alt="product.name"/>
</li>
<t t-if="len(image_ids)" t-foreach="image_ids" t-as="pimg">
<li data-target="#o-carousel-product" t-att-data-slide-to="pimg_index + (variant_img and 2 or 1)">
@@ -1,8 +1,14 @@
$(document).ready(function () {
// When choosing an delivery carrier, update the quotation and the acquirers
var $pay_button = $('.oe_sale_acquirer_button button');
$pay_button.prop('disabled', false);
// When choosing an delivery carrier, update the quotation and the acquirers. Disable the 'Pay
// Now' button to avoid being redirected to payment acquier if the delivery carrier update is
// not over.
var $carrier = $("#delivery_carrier");
$carrier.find("input[name='delivery_type']").click(function (ev) {
$pay_button.prop('disabled', true);
var carrier_id = $(ev.currentTarget).val();
window.location.href = '/shop/payment?carrier_id=' + carrier_id;
});
+3 -1
View File
@@ -1532,7 +1532,9 @@ class IrModelData(models.Model):
if model == 'ir.model.fields':
# Don't remove the LOG_ACCESS_COLUMNS unless _log_access
# has been turned off on the model.
field = self.env[model].browse(res_id)
field = self.env[model].browse(res_id).with_context(
prefetch_fields=False,
)
if not field.exists():
_logger.info('Deleting orphan external_ids %s', external_ids)
external_ids.unlink()
+5 -4
View File
@@ -383,11 +383,12 @@ try:
# TODO when xlsxwriter bump to 0.9.8, add worksheet_class=None parameter instead of kw
def add_worksheet(self, name=None, **kw):
# invalid Excel character: []:*?/\
name = re.sub(r'[\[\]:*?/\\]', '', name)
if name:
# invalid Excel character: []:*?/\
name = re.sub(r'[\[\]:*?/\\]', '', name)
# maximum size is 31 characters
name = name[:31]
# maximum size is 31 characters
name = name[:31]
return super(PatchedXlsxWorkbook, self).add_worksheet(name, **kw)
xlsxwriter.Workbook = PatchedXlsxWorkbook
+1 -1
View File
@@ -23,7 +23,7 @@ _CONFDELTYPES = {
def table_exists(cr, tablename):
""" Return whether the given table exists. """
query = "SELECT 1 FROM information_schema.tables WHERE table_name=%s"
query = "SELECT 1 FROM pg_class WHERE relkind IN ('r', 'v', 'm') AND relname=%s"
cr.execute(query, (tablename,))
return cr.rowcount