mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-10-25 23:40:05 -05:00
[PATCH] Upstream patch - 16112022
This commit is contained in:
1 parent
d9bd47460f
commit
af31b403e3
13 files changed
+155
-19
No files matched your search
@@ -543,6 +543,10 @@ class ResPartner(models.Model):
|
||||
stdnum_vat_format = getattr(stdnum.util.get_cc_module('ch', 'vat'), 'format', None)
|
||||
return stdnum_vat_format('CH' + vat)[2:] if stdnum_vat_format else vat
|
||||
|
||||
def format_vat_sm(self, vat):
|
||||
stdnum_vat_format = stdnum.util.get_cc_module('sm', 'vat').compact
|
||||
return stdnum_vat_format('SM' + vat)[2:]
|
||||
|
||||
def _fix_vat_number(self, vat, country_id):
|
||||
code = self.env['res.country'].browse(country_id).code if country_id else False
|
||||
vat_country, vat_number = self._split_vat(vat)
|
||||
|
||||
@@ -58,7 +58,7 @@ class Employee(models.AbstractModel):
|
||||
|
||||
|
||||
# Check on IP
|
||||
if literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr.hr_presence_control_ip', 'False')):
|
||||
if literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_ip', 'False')):
|
||||
ip_list = company.hr_presence_control_ip_list
|
||||
ip_list = ip_list.split(',') if ip_list else []
|
||||
ip_employees = self.env['hr.employee']
|
||||
@@ -74,7 +74,7 @@ class Employee(models.AbstractModel):
|
||||
employees = employees - ip_employees
|
||||
|
||||
# Check on sent emails
|
||||
if literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr.hr_presence_control_email', 'False')):
|
||||
if literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_email', 'False')):
|
||||
email_employees = self.env['hr.employee']
|
||||
threshold = company.hr_presence_control_email_amount
|
||||
for employee in employees:
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
<field name="property_stock_account_input_categ_id" ref="l10n_de_skr03.account_3970"/>
|
||||
<field name="property_stock_account_output_categ_id" ref="l10n_de_skr03.account_3980"/>
|
||||
<field name="property_stock_valuation_account_id" ref="l10n_de_skr03.account_3960"/>
|
||||
<field name="property_tax_payable_account_id" ref="l10n_de_skr03.account_1797"/>
|
||||
<field name="property_tax_receivable_account_id" ref="l10n_de_skr03.account_1545"/>
|
||||
<field name="property_advance_tax_payment_account_id" ref="l10n_de_skr03.account_1780"/>
|
||||
<field name="income_currency_exchange_account_id" ref="l10n_de_skr03.account_2660"/>
|
||||
<field name="expense_currency_exchange_account_id" ref="l10n_de_skr03.account_2150"/>
|
||||
<field name="default_pos_receivable_account_id" ref="l10n_de_skr03.account_1411" />
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<field name="property_account_payable_id" ref="l10n_de_skr04.chart_skr04_3301"/>
|
||||
<field name="property_account_expense_categ_id" ref="l10n_de_skr04.chart_skr04_5400"/>
|
||||
<field name="property_account_income_categ_id" ref="l10n_de_skr04.chart_skr04_4400"/>
|
||||
<field name="property_tax_payable_account_id" ref="l10n_de_skr04.chart_skr04_3860"/>
|
||||
<field name="property_tax_receivable_account_id" ref="l10n_de_skr04.chart_skr04_1421"/>
|
||||
<field name="property_advance_tax_payment_account_id" ref="l10n_de_skr04.chart_skr04_3820"/>
|
||||
<field name="income_currency_exchange_account_id" ref="l10n_de_skr04.chart_skr04_4840"/>
|
||||
<field name="expense_currency_exchange_account_id" ref="l10n_de_skr04.chart_skr04_6880"/>
|
||||
<field name="default_pos_receivable_account_id" ref="l10n_de_skr04.chart_skr04_1206" />
|
||||
|
||||
@@ -345,6 +345,10 @@ class MaintenanceRequest(models.Model):
|
||||
request._add_followers()
|
||||
if request.equipment_id and not request.maintenance_team_id:
|
||||
request.maintenance_team_id = request.equipment_id.maintenance_team_id
|
||||
if not request.stage_id.done:
|
||||
request.close_date = False
|
||||
elif request.stage_id.done and not request.close_date:
|
||||
request.close_date = fields.Date.today()
|
||||
request.activity_update()
|
||||
return request
|
||||
|
||||
@@ -358,7 +362,9 @@ class MaintenanceRequest(models.Model):
|
||||
self._add_followers()
|
||||
if 'stage_id' in vals:
|
||||
self.filtered(lambda m: m.stage_id.done).write({'close_date': fields.Date.today()})
|
||||
self.filtered(lambda m: not m.stage_id.done).write({'close_date': False})
|
||||
self.activity_feedback(['maintenance.mail_act_maintenance_request'])
|
||||
self.activity_update()
|
||||
if vals.get('user_id') or vals.get('schedule_date'):
|
||||
self.activity_update()
|
||||
if vals.get('equipment_id'):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import stock_move
|
||||
from . import stock_picking
|
||||
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = "stock.move"
|
||||
|
||||
def _is_purchase_return(self):
|
||||
res = super()._is_purchase_return()
|
||||
return res or self._is_dropshipped_returned()
|
||||
|
||||
def _is_dropshipped(self):
|
||||
res = super()._is_dropshipped()
|
||||
return res or (
|
||||
self.partner_id.property_stock_subcontractor.parent_path
|
||||
and self.partner_id.property_stock_subcontractor.parent_path in self.location_id.parent_path
|
||||
and self.location_dest_id.usage == 'customer'
|
||||
)
|
||||
|
||||
def _is_dropshipped_returned(self):
|
||||
res = super()._is_dropshipped_returned()
|
||||
return res or (
|
||||
self.location_id.usage == 'customer'
|
||||
and self.partner_id.property_stock_subcontractor.parent_path
|
||||
and self.partner_id.property_stock_subcontractor.parent_path in self.location_dest_id.parent_path
|
||||
)
|
||||
@@ -138,7 +138,9 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon):
|
||||
def test_po_to_customer(self):
|
||||
"""
|
||||
Create and confirm a PO with a subcontracted move. The picking type of
|
||||
the PO is 'Dropship' and the delivery address a customer.
|
||||
the PO is 'Dropship' and the delivery address a customer. Then, process
|
||||
a return with the stock location as destination and another return with
|
||||
the supplier as destination
|
||||
"""
|
||||
subcontractor, client = self.env['res.partner'].create([
|
||||
{'name': 'SuperSubcontractor'},
|
||||
@@ -177,7 +179,7 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon):
|
||||
"order_line": [(0, 0, {
|
||||
'product_id': p_finished.id,
|
||||
'name': p_finished.name,
|
||||
'product_qty': 1.0,
|
||||
'product_qty': 2.0,
|
||||
})],
|
||||
})
|
||||
po.button_confirm()
|
||||
@@ -186,11 +188,45 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon):
|
||||
self.assertEqual(mo.picking_type_id, self.warehouse.subcontracting_type_id)
|
||||
|
||||
delivery = po.picking_ids
|
||||
delivery.move_line_ids.qty_done = 1.0
|
||||
delivery.move_line_ids.qty_done = 2.0
|
||||
delivery.button_validate()
|
||||
|
||||
self.assertEqual(delivery.state, 'done')
|
||||
self.assertEqual(mo.state, 'done')
|
||||
self.assertEqual(po.order_line.qty_received, 2)
|
||||
|
||||
# return 1 x P_finished to the stock location
|
||||
stock_location = self.warehouse.lot_stock_id
|
||||
stock_location.return_location = True
|
||||
return_form = Form(self.env['stock.return.picking'].with_context(active_ids=delivery.ids, active_id=delivery.id, active_model='stock.picking'))
|
||||
with return_form.product_return_moves.edit(0) as line:
|
||||
line.quantity = 1.0
|
||||
return_form.location_id = stock_location
|
||||
return_wizard = return_form.save()
|
||||
return_picking_id, _pick_type_id = return_wizard._create_returns()
|
||||
|
||||
delivery_return01 = self.env['stock.picking'].browse(return_picking_id)
|
||||
delivery_return01.move_line_ids.qty_done = 1.0
|
||||
delivery_return01.button_validate()
|
||||
|
||||
self.assertEqual(delivery_return01.state, 'done')
|
||||
self.assertEqual(p_finished.qty_available, 1, 'One product has been returned to the stock location, so it should be available')
|
||||
self.assertEqual(po.order_line.qty_received, 2, 'One product has been returned to the stock location, so we should still consider it as received')
|
||||
|
||||
# return 1 x P_finished to the supplier location
|
||||
supplier_location = dropship_picking_type.default_location_src_id
|
||||
return_form = Form(self.env['stock.return.picking'].with_context(active_ids=delivery.ids, active_id=delivery.id, active_model='stock.picking'))
|
||||
with return_form.product_return_moves.edit(0) as line:
|
||||
line.quantity = 1.0
|
||||
return_form.location_id = supplier_location
|
||||
return_wizard = return_form.save()
|
||||
return_picking_id, _pick_type_id = return_wizard._create_returns()
|
||||
|
||||
delivery_return02 = self.env['stock.picking'].browse(return_picking_id)
|
||||
delivery_return02.move_line_ids.qty_done = 1.0
|
||||
delivery_return02.button_validate()
|
||||
|
||||
self.assertEqual(delivery_return02.state, 'done')
|
||||
self.assertEqual(po.order_line.qty_received, 1)
|
||||
|
||||
def test_po_to_subcontractor(self):
|
||||
|
||||
@@ -294,7 +294,7 @@ class PurchaseOrderLine(models.Model):
|
||||
# the PO. Therefore, we can skip them since they will be handled later on.
|
||||
for move in line.move_ids.filtered(lambda m: m.product_id == line.product_id):
|
||||
if move.state == 'done':
|
||||
if move.location_dest_id.usage == "supplier":
|
||||
if move._is_purchase_return():
|
||||
if move.to_refund:
|
||||
total -= move.product_uom._compute_quantity(move.product_uom_qty, line.product_uom, rounding_method='HALF-UP')
|
||||
elif move.origin_returned_move_id and move.origin_returned_move_id._is_dropshipped() and not move._is_dropshipped_returned():
|
||||
@@ -303,17 +303,6 @@ class PurchaseOrderLine(models.Model):
|
||||
# receive the product physically in our stock. To avoid counting the
|
||||
# quantity twice, we do nothing.
|
||||
pass
|
||||
elif (
|
||||
move.location_dest_id.usage == "internal"
|
||||
and move.location_id.usage != "supplier"
|
||||
and move.warehouse_id
|
||||
and move.location_dest_id
|
||||
not in self.env["stock.location"].search(
|
||||
[("id", "child_of", move.warehouse_id.view_location_id.id)]
|
||||
)
|
||||
):
|
||||
if move.to_refund:
|
||||
total -= move.product_uom._compute_quantity(move.product_uom_qty, line.product_uom, rounding_method='HALF-UP')
|
||||
else:
|
||||
total += move.product_uom._compute_quantity(move.product_uom_qty, line.product_uom, rounding_method='HALF-UP')
|
||||
line._track_qty_received(total)
|
||||
|
||||
@@ -135,6 +135,15 @@ class StockMove(models.Model):
|
||||
_('Flectra is not able to generate the anglo saxon entries. The total valuation of %s is zero.') % related_aml.product_id.display_name)
|
||||
return valuation_price_unit_total, valuation_total_qty
|
||||
|
||||
def _is_purchase_return(self):
|
||||
self.ensure_one()
|
||||
return self.location_dest_id.usage == "supplier" or (
|
||||
self.location_dest_id.usage == "internal"
|
||||
and self.location_id.usage != "supplier"
|
||||
and self.warehouse_id
|
||||
and self.location_dest_id not in self.env["stock.location"].search([("id", "child_of", self.warehouse_id.view_location_id.id)])
|
||||
)
|
||||
|
||||
|
||||
class StockWarehouse(models.Model):
|
||||
_inherit = 'stock.warehouse'
|
||||
|
||||
@@ -143,7 +143,7 @@ class SnailmailLetter(models.Model):
|
||||
paperformat = report.get_paperformat()
|
||||
if (paperformat.format == 'custom' and paperformat.page_width != 210 and paperformat.page_height != 297) or paperformat.format != 'A4':
|
||||
raise UserError(_("Please use an A4 Paper format."))
|
||||
pdf_bin, unused_filetype = report.with_context(snailmail_layout=not self.cover, lang='en_US').render_qweb_pdf(self.res_id)
|
||||
pdf_bin, unused_filetype = report.with_context(snailmail_layout=not self.cover, lang='en_US')._render_qweb_pdf(self.res_id)
|
||||
if self.cover:
|
||||
pdf_bin = self._append_cover_page(pdf_bin)
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
|
||||
@@ -16,6 +16,7 @@ var dom = require('web.dom');
|
||||
var ListRenderer = require('web.ListRenderer');
|
||||
var utils = require('web.utils');
|
||||
const { WidgetAdapterMixin } = require('web.OwlCompatibility');
|
||||
const concurrency = require('web.concurrency');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
@@ -97,6 +98,8 @@ ListRenderer.include({
|
||||
this.currentFieldIndex = null;
|
||||
this.isResizing = false;
|
||||
this.eventListeners = [];
|
||||
|
||||
this.rowModeChangeMutex = new concurrency.Mutex();
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
@@ -404,7 +407,12 @@ ListRenderer.include({
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setRowMode: function (recordID, mode) {
|
||||
var self = this;
|
||||
// Use a mutex because we don't want to rerender a row before the previous render is finished
|
||||
return this.rowModeChangeMutex.exec(this._setRowMode.bind(this, recordID, mode));
|
||||
},
|
||||
|
||||
_setRowMode: async function (recordID, mode) {
|
||||
const self = this;
|
||||
var record = self._getRecord(recordID);
|
||||
if (!record) {
|
||||
return Promise.resolve();
|
||||
@@ -471,6 +479,7 @@ ListRenderer.include({
|
||||
core.bus.trigger('DOM_updated');
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is called whenever we click/move outside of a row that was
|
||||
* in edit mode. This is the moment we save all accumulated changes on that
|
||||
|
||||
@@ -11811,6 +11811,54 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('quickly setting row mode with owl_compatibility', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
this.data.bar.fields.bool = { string: 'bool', type: 'boolean' };
|
||||
this.data.foo.records[0].o2m = [1, 2, 3];
|
||||
|
||||
const form = await createView({
|
||||
View: FormView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
res_id: 1,
|
||||
viewOptions: { mode: 'edit' },
|
||||
arch: `<form>
|
||||
<sheet>
|
||||
<notebook>
|
||||
<page>
|
||||
<field name="o2m">
|
||||
<tree editable="bottom">
|
||||
<field name="bool"/>
|
||||
<field name="display_name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
await testUtils.dom.click(form.$('tbody tr:eq(0) td:eq(1)'));
|
||||
await testUtils.fields.editInput(form.$('input[name=display_name]'), 'another value');
|
||||
|
||||
// Double-click on a field of the second row
|
||||
testUtils.dom.click(form.$('tbody tr:eq(1) td:eq(1)'));
|
||||
testUtils.dom.click(form.$('tbody tr:eq(1) td:eq(1)'));
|
||||
await testUtils.nextTick();
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.strictEqual(
|
||||
form.el.querySelector('tr:nth-child(1) > td.o_data_cell.o_field_cell.o_list_char').textContent,
|
||||
'another value');
|
||||
|
||||
const rows = form.$('.o_data_row .o_list_char');
|
||||
assert.containsNone(rows[0], 'input'); // this means that the first row is saved
|
||||
assert.containsOnce(rows[1], 'input'); // this means that the second row is in edit mode
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Reference in new issue
Block a user