mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-08-19 01:34:43 -05:00
[PATCH] Upstream patch - 13102021
This commit is contained in:
@@ -214,9 +214,9 @@ class AccountBankStatement(models.Model):
|
||||
reference = fields.Char(string='External Reference', states={'open': [('readonly', False)]}, copy=False, readonly=True, help="Used to hold the reference of the external mean that created this statement (name of imported file, reference of online synchronization...)")
|
||||
date = fields.Date(required=True, states={'confirm': [('readonly', True)]}, index=True, copy=False, default=fields.Date.context_today)
|
||||
date_done = fields.Datetime(string="Closed On")
|
||||
balance_start = fields.Monetary(string='Starting Balance', states={'confirm': [('readonly', True)]}, compute='_compute_starting_balance', readonly=False, store=True)
|
||||
balance_end_real = fields.Monetary('Ending Balance', states={'confirm': [('readonly', True)]}, compute='_compute_ending_balance', readonly=False, store=True)
|
||||
state = fields.Selection(string='Status', required=True, readonly=True, copy=False, selection=[
|
||||
balance_start = fields.Monetary(string='Starting Balance', states={'confirm': [('readonly', True)]}, compute='_compute_starting_balance', readonly=False, store=True, tracking=True)
|
||||
balance_end_real = fields.Monetary('Ending Balance', states={'confirm': [('readonly', True)]}, compute='_compute_ending_balance', readonly=False, store=True, tracking=True)
|
||||
state = fields.Selection(string='Status', required=True, readonly=True, copy=False, tracking=True, selection=[
|
||||
('open', 'New'),
|
||||
('posted', 'Processing'),
|
||||
('confirm', 'Validated'),
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<field name="name">account.move.line.kanban</field>
|
||||
<field name="model">account.move.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="o_kanban_mobile" create="false">
|
||||
<kanban class="o_kanban_mobile" create="false" group_create="false">
|
||||
<field name="date_maturity"/>
|
||||
<field name="move_id"/>
|
||||
<field name="name"/>
|
||||
|
||||
@@ -120,10 +120,13 @@ class AccountMoveReversal(models.TransientModel):
|
||||
action.update({
|
||||
'view_mode': 'form',
|
||||
'res_id': moves_to_redirect.id,
|
||||
'context': {'default_move_type': moves_to_redirect.move_type},
|
||||
})
|
||||
else:
|
||||
action.update({
|
||||
'view_mode': 'tree,form',
|
||||
'domain': [('id', 'in', moves_to_redirect.ids)],
|
||||
})
|
||||
if len(set(moves_to_redirect.mapped('move_type'))) == 1:
|
||||
action['context'] = {'default_move_type': moves_to_redirect.mapped('move_type').pop()}
|
||||
return action
|
||||
|
||||
@@ -76,7 +76,8 @@ class AccountDebitNote(models.TransientModel):
|
||||
'name': _('Debit Notes'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'account.move',
|
||||
}
|
||||
'context': {'default_move_type': default_values['move_type']},
|
||||
}
|
||||
if len(new_moves) == 1:
|
||||
action.update({
|
||||
'view_mode': 'form',
|
||||
|
||||
@@ -91,10 +91,10 @@ class ResPartner(models.Model):
|
||||
if fragment:
|
||||
query['redirect'] = base + werkzeug.urls.url_encode(fragment)
|
||||
|
||||
url = "/web/%s?%s" % (route, werkzeug.urls.url_encode(query))
|
||||
signup_url = "/web/%s?%s" % (route, werkzeug.urls.url_encode(query))
|
||||
if not self.env.context.get('relative_url'):
|
||||
url = werkzeug.urls.url_join(base_url, url)
|
||||
res[partner.id] = url
|
||||
signup_url = werkzeug.urls.url_join(base_url, signup_url)
|
||||
res[partner.id] = signup_url
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@@ -1063,7 +1063,7 @@ class Message(models.Model):
|
||||
('res_id', 'in', moderated_channel_ids),
|
||||
'|',
|
||||
('author_id', '=', self.env.user.partner_id.id),
|
||||
('moderation_status', '=', 'pending_moderation'),
|
||||
('need_moderation', '=', True),
|
||||
]
|
||||
messages |= self.search(moderated_messages_dom, limit=limit)
|
||||
# Truncate the results to `limit`
|
||||
|
||||
@@ -1748,7 +1748,13 @@ class MrpProduction(models.Model):
|
||||
duplicates_unbuild = self.env['stock.move.line'].search_count(domain_unbuild + [
|
||||
('move_id.unbuild_id', '!=', False)
|
||||
])
|
||||
if not (duplicates_unbuild and duplicates - duplicates_unbuild == 0):
|
||||
removed = self.env['stock.move.line'].search_count([
|
||||
('lot_id', '=', move_line.lot_id.id),
|
||||
('state', '=', 'done'),
|
||||
('location_dest_id.scrap_location', '=', True)
|
||||
])
|
||||
# Either removed or unbuild
|
||||
if not ((duplicates_unbuild or removed) and duplicates - duplicates_unbuild - removed == 0):
|
||||
raise UserError(message)
|
||||
# Check presence of same sn in current production
|
||||
duplicates = co_prod_move_lines.filtered(lambda ml: ml.qty_done and ml.lot_id == move_line.lot_id) - move_line
|
||||
@@ -1784,7 +1790,13 @@ class MrpProduction(models.Model):
|
||||
duplicates_unbuild = self.env['stock.move.line'].search_count(domain_unbuild + [
|
||||
('move_id.unbuild_id', '!=', False)
|
||||
])
|
||||
if not (duplicates_unbuild and duplicates - duplicates_unbuild == 0):
|
||||
removed = self.env['stock.move.line'].search_count([
|
||||
('lot_id', '=', move_line.lot_id.id),
|
||||
('state', '=', 'done'),
|
||||
('location_dest_id.scrap_location', '=', True)
|
||||
])
|
||||
# Either removed or unbuild
|
||||
if not ((duplicates_unbuild or removed) and duplicates - duplicates_unbuild - removed == 0):
|
||||
raise UserError(message)
|
||||
# Check presence of same sn in current production
|
||||
duplicates = co_prod_move_lines.filtered(lambda ml: ml.qty_done and ml.lot_id == move_line.lot_id) - move_line
|
||||
|
||||
@@ -5,6 +5,8 @@ from flectra.tests import Form, tagged
|
||||
from flectra.addons.mrp.tests.common import TestMrpCommon
|
||||
import uuid
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestTraceability(TestMrpCommon):
|
||||
TRACKING_TYPES = ['none', 'serial', 'lot']
|
||||
|
||||
@@ -306,3 +308,83 @@ class TestTraceability(TestMrpCommon):
|
||||
self.assertEqual(byproduct_move_line_2_lot_1.consume_line_ids.filtered(lambda l: l.qty_done), raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1)
|
||||
byproduct_move_line_2_lot_2 = finished_move_lines.filtered(lambda ml: ml.lot_id.name == 'Byproduct_2_lot_2')
|
||||
self.assertEqual(byproduct_move_line_2_lot_2.consume_line_ids, raw_line_raw_1_lot_2 | raw_line_raw_2_lot_2)
|
||||
|
||||
def test_tracking_repair_production(self):
|
||||
"""
|
||||
Test that removing a tracked component with a repair does not block the flow of using that component in another
|
||||
bom
|
||||
"""
|
||||
if 'repair.order' not in self.env: # Module required for that test
|
||||
return
|
||||
product_to_repair = self.env['product.product'].create({
|
||||
'name': 'product first serial to act repair',
|
||||
'tracking': 'serial',
|
||||
})
|
||||
ptrepair_lot = self.env['stock.production.lot'].create({
|
||||
'name': 'A1',
|
||||
'product_id': product_to_repair.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
product_to_remove = self.env['product.product'].create({
|
||||
'name': 'other first serial to remove with repair',
|
||||
'tracking': 'serial',
|
||||
})
|
||||
ptremove_lot = self.env['stock.production.lot'].create({
|
||||
'name': 'B2',
|
||||
'product_id': product_to_remove.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
# Create a manufacturing order with product (with SN A1)
|
||||
mo = self.env['mrp.production'].create({
|
||||
'name': 'testing',
|
||||
'product_id': product_to_repair.id,
|
||||
'product_uom_id': product_to_repair.uom_id.id,
|
||||
'product_qty': 1
|
||||
})
|
||||
mo_form = Form(mo)
|
||||
with mo_form.move_raw_ids.new() as move:
|
||||
move.product_id = product_to_remove
|
||||
move.product_uom_qty = 1
|
||||
move.move_line_ids.lot_id = ptremove_lot # Set component serial to B2
|
||||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
# Set serial to A1
|
||||
mo.lot_producing_id = ptrepair_lot
|
||||
mo.button_mark_done()
|
||||
|
||||
with Form(self.env['repair.order']) as ro_form:
|
||||
ro_form.name = 'Please repair'
|
||||
ro_form.product_id = product_to_repair
|
||||
ro_form.lot_id = ptrepair_lot # Repair product Serial A1
|
||||
with ro_form.operations.new() as operation:
|
||||
operation.type = 'remove'
|
||||
operation.product_id = product_to_remove
|
||||
operation.lot_id = ptremove_lot # Remove product Serial B2 from the product
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.action_repair_start()
|
||||
ro.action_repair_end()
|
||||
|
||||
# Create a manufacturing order with product (with SN A2)
|
||||
mo2 = self.env['mrp.production'].create({
|
||||
'name': 'testing duo',
|
||||
'product_id': product_to_repair.id,
|
||||
'product_uom_id': product_to_repair.uom_id.id,
|
||||
'product_qty': 1
|
||||
})
|
||||
mo2_form = Form(mo2)
|
||||
with mo2_form.move_raw_ids.new() as move:
|
||||
move.product_id = product_to_remove
|
||||
move.product_uom_qty = 1
|
||||
move.move_line_ids.lot_id = ptremove_lot # Set component serial to B2 again, it is possible
|
||||
mo2 = mo2_form.save()
|
||||
mo2.action_confirm()
|
||||
# Set serial to A2
|
||||
mo2.lot_producing_id = self.env['stock.production.lot'].create({
|
||||
'name': 'A2',
|
||||
'product_id': product_to_repair.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
# We are not forbidden to use that serial number, so nothing raised here
|
||||
mo2.button_mark_done()
|
||||
|
||||
|
||||
@@ -574,7 +574,8 @@ class PosConfig(models.Model):
|
||||
}
|
||||
|
||||
def _force_http(self):
|
||||
if self.other_devices:
|
||||
enforce_https = self.env['ir.config_parameter'].sudo().get_param('point_of_sale.enforce_https')
|
||||
if not enforce_https and self.other_devices:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -553,11 +553,11 @@ class PosSession(models.Model):
|
||||
exp_key = move.product_id._get_product_accounts()['expense']
|
||||
out_key = move.product_id.categ_id.property_stock_account_output_categ_id
|
||||
amount = -sum(move.stock_valuation_layer_ids.mapped('value'))
|
||||
stock_expense[exp_key] = self._update_amounts(stock_expense[exp_key], {'amount': amount}, move.picking_id.date)
|
||||
stock_expense[exp_key] = self._update_amounts(stock_expense[exp_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
if move.location_id.usage == 'customer':
|
||||
stock_return[out_key] = self._update_amounts(stock_return[out_key], {'amount': amount}, move.picking_id.date)
|
||||
stock_return[out_key] = self._update_amounts(stock_return[out_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
else:
|
||||
stock_output[out_key] = self._update_amounts(stock_output[out_key], {'amount': amount}, move.picking_id.date)
|
||||
stock_output[out_key] = self._update_amounts(stock_output[out_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
|
||||
MoveLine = self.env['account.move.line'].with_context(check_move_validity=False)
|
||||
|
||||
data.update({
|
||||
|
||||
@@ -32,7 +32,8 @@ class PosConfig(models.Model):
|
||||
self.set_tip_after_payment = False
|
||||
|
||||
def _force_http(self):
|
||||
if self.printer_ids.filtered(lambda pt: pt.printer_type == 'epson_epos'):
|
||||
enforce_https = self.env['ir.config_parameter'].sudo().get_param('point_of_sale.enforce_https')
|
||||
if not enforce_https and self.printer_ids.filtered(lambda pt: pt.printer_type == 'epson_epos'):
|
||||
return True
|
||||
return super(PosConfig, self)._force_http()
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ class PosConfig(models.Model):
|
||||
_inherit = 'pos.config'
|
||||
|
||||
def _force_http(self):
|
||||
if self.payment_method_ids.filtered(lambda pm: pm.use_payment_terminal == 'six'):
|
||||
enforce_https = self.env['ir.config_parameter'].sudo().get_param('point_of_sale.enforce_https')
|
||||
if not enforce_https and self.payment_method_ids.filtered(lambda pm: pm.use_payment_terminal == 'six'):
|
||||
return True
|
||||
return super(PosConfig, self)._force_http()
|
||||
|
||||
@@ -166,6 +166,10 @@ flectra.define('web.CustomFilterItem', function (require) {
|
||||
val => field_utils.format[type](val, { type }, { timezone: false })
|
||||
);
|
||||
descriptionArray.push(`"${dateValue.join(" " + this.env._t("and") + " ")}"`);
|
||||
} else if (type === "selection") {
|
||||
domainValue = [condition.value];
|
||||
const formattedValue = field_utils.format[type](condition.value, field);
|
||||
descriptionArray.push(`"${formattedValue}"`);
|
||||
} else {
|
||||
domainValue = [condition.value];
|
||||
descriptionArray.push(`"${condition.value}"`);
|
||||
|
||||
@@ -91,7 +91,7 @@ flectra.define('web.filter_menu_generator_tests', function (require) {
|
||||
|
||||
// Default value
|
||||
expectedFilters = [{
|
||||
description: 'Color is "black"',
|
||||
description: 'Color is "Black"',
|
||||
domain: '[["color","=","black"]]',
|
||||
type: 'filter',
|
||||
}];
|
||||
@@ -101,7 +101,7 @@ flectra.define('web.filter_menu_generator_tests', function (require) {
|
||||
|
||||
// Updated value
|
||||
expectedFilters = [{
|
||||
description: 'Color is "white"',
|
||||
description: 'Color is "White"',
|
||||
domain: '[["color","=","white"]]',
|
||||
type: 'filter',
|
||||
}];
|
||||
|
||||
@@ -238,17 +238,24 @@ publicWidget.registry.StandardAffixedHeader = BaseAnimatedHeader.extend({
|
||||
|
||||
const mainPosScrolled = (scroll > this.headerHeight + this.topGap);
|
||||
const reachPosScrolled = (scroll > this.scrolledPoint + this.topGap);
|
||||
const fixedUpdate = (this.fixedHeader !== mainPosScrolled);
|
||||
const showUpdate = (this.fixedHeaderShow !== reachPosScrolled);
|
||||
|
||||
// Switch between static/fixed position of the header
|
||||
if (this.fixedHeader !== mainPosScrolled) {
|
||||
this.$el.css('transform', mainPosScrolled ? 'translate(0, -100%)' : '');
|
||||
if (fixedUpdate || showUpdate) {
|
||||
this.$el.css('transform',
|
||||
reachPosScrolled
|
||||
? `translate(0, -${this.topGap}px)`
|
||||
: mainPosScrolled
|
||||
? 'translate(0, -100%)'
|
||||
: '');
|
||||
void this.$el[0].offsetWidth; // Force a paint refresh
|
||||
this._toggleFixedHeader(mainPosScrolled);
|
||||
}
|
||||
// Show/hide header
|
||||
if (this.fixedHeaderShow !== reachPosScrolled) {
|
||||
this.$el.css('transform', reachPosScrolled ? `translate(0, -${this.topGap}px)` : 'translate(0, -100%)');
|
||||
this.fixedHeaderShow = reachPosScrolled;
|
||||
|
||||
this.fixedHeaderShow = reachPosScrolled;
|
||||
|
||||
if (fixedUpdate) {
|
||||
this._toggleFixedHeader(mainPosScrolled);
|
||||
} else if (showUpdate) {
|
||||
this._adaptToHeaderChange();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -70,11 +70,10 @@
|
||||
<!-- Note: no need of extra dependency thanks to the apply-to -->
|
||||
</t>
|
||||
</div>
|
||||
<div data-selector=".s_product_catalog_dish"/>
|
||||
<div data-selector=".s_product_catalog_dish" data-drop-near=".s_product_catalog_dish"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@data-js='SnippetMove']" position="attributes">
|
||||
<attribute name="data-selector" add=".s_product_catalog_dish" separator=","/>
|
||||
<attribute name="data-drop-near" add=".s_product_catalog_dish" separator=","/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user