mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-10-25 15:30:05 -05:00
[PATCH] Upstream patch - 10032022
This commit is contained in:
1 parent
4215d5c13b
commit
c09790d106
10 files changed
+88
-20
No files matched your search
@@ -146,9 +146,19 @@ class User(models.Model):
|
||||
# Note: limit the `sudo` to the only action of "editing own profile" action in order to
|
||||
# avoid breaking `groups` mecanism on res.users form view.
|
||||
profile_view = self.env.ref("hr.res_users_view_form_profile")
|
||||
original_user = self.env.user
|
||||
if profile_view and view_id == profile_view.id:
|
||||
self = self.with_user(SUPERUSER_ID)
|
||||
return super(User, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
|
||||
result = super(User, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
|
||||
# Due to using the SUPERUSER the result will contain action that the user may not have access too
|
||||
# here we filter out actions that requires special implicit rights to avoid having unusable actions
|
||||
# in the dropdown menu.
|
||||
if toolbar and self.env.user != original_user:
|
||||
self = self.with_user(original_user.id)
|
||||
if not self.user_has_groups("base.group_erp_manager"):
|
||||
change_password_action = self.env.ref("base.change_password_wizard_action")
|
||||
result['toolbar']['action'] = [act for act in result['toolbar']['action'] if act['id'] != change_password_action.id]
|
||||
return result
|
||||
|
||||
def write(self, vals):
|
||||
"""
|
||||
|
||||
@@ -76,6 +76,32 @@ class TestSelfAccessProfile(TestHrCommon):
|
||||
# Compare both
|
||||
self.assertEqual(full_fields.keys(), fields.keys(), "View fields should not depend on user's groups")
|
||||
|
||||
def test_access_my_profile_toolbar(self):
|
||||
""" A simple user shouldn't have the possibilities to see the 'Change Password' action"""
|
||||
james = new_test_user(self.env, login='jam', groups='base.group_user', name='Simple employee', email='jam@example.com')
|
||||
james = james.with_user(james)
|
||||
self.env['hr.employee'].create({
|
||||
'name': 'James',
|
||||
'user_id': james.id,
|
||||
})
|
||||
view = self.env.ref('hr.res_users_view_form_profile')
|
||||
available_actions = james.fields_view_get(view_id=view.id, toolbar=True)['toolbar']['action']
|
||||
change_password_action = self.env.ref("base.change_password_wizard_action")
|
||||
|
||||
self.assertFalse(any(x['id'] == change_password_action.id for x in available_actions))
|
||||
|
||||
""" An ERP manager should have the possibilities to see the 'Change Password' """
|
||||
john = new_test_user(self.env, login='joh', groups='base.group_erp_manager', name='ERP Manager', email='joh@example.com')
|
||||
john = john.with_user(john)
|
||||
self.env['hr.employee'].create({
|
||||
'name': 'John',
|
||||
'user_id': john.id,
|
||||
})
|
||||
view = self.env.ref('hr.res_users_view_form_profile')
|
||||
available_actions = john.fields_view_get(view_id=view.id, toolbar=True)['toolbar']['action']
|
||||
self.assertTrue(any(x['id'] == change_password_action.id for x in available_actions))
|
||||
|
||||
|
||||
class TestSelfAccessRights(TestHrCommon):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<form position="attributes">
|
||||
<attribute name="create">false</attribute>
|
||||
<attribute name="delete">false</attribute>
|
||||
<attribute name="js_class">hr_employee_profile_form</attribute>
|
||||
</form>
|
||||
<notebook position="replace">
|
||||
|
||||
@@ -118,6 +118,10 @@
|
||||
'repartition_type': 'base',
|
||||
'plus_report_line_ids': [ref('tax_report_base_turnover_0_vat')],
|
||||
}),
|
||||
(0,0, {
|
||||
'factor_percent': 100,
|
||||
'repartition_type': 'tax',
|
||||
}),
|
||||
]"/>
|
||||
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
|
||||
(0,0, {
|
||||
@@ -125,6 +129,10 @@
|
||||
'repartition_type': 'base',
|
||||
'minus_report_line_ids': [ref('tax_report_base_turnover_0_vat')],
|
||||
}),
|
||||
(0,0, {
|
||||
'factor_percent': 100,
|
||||
'repartition_type': 'tax',
|
||||
}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -1949,6 +1949,10 @@
|
||||
'repartition_type': 'base',
|
||||
'plus_report_line_ids': [ref('l10n_fr.tax_report_02')],
|
||||
}),
|
||||
(0,0, {
|
||||
'factor_percent': 100,
|
||||
'repartition_type': 'tax',
|
||||
}),
|
||||
]"/>
|
||||
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
|
||||
(0,0, {
|
||||
@@ -1956,6 +1960,10 @@
|
||||
'repartition_type': 'base',
|
||||
'minus_report_line_ids': [ref('l10n_fr.tax_report_02')],
|
||||
}),
|
||||
(0,0, {
|
||||
'factor_percent': 100,
|
||||
'repartition_type': 'tax',
|
||||
}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
@@ -1974,6 +1982,10 @@
|
||||
'repartition_type': 'base',
|
||||
'plus_report_line_ids': [ref('l10n_fr.tax_report_04')],
|
||||
}),
|
||||
(0,0, {
|
||||
'factor_percent': 100,
|
||||
'repartition_type': 'tax',
|
||||
}),
|
||||
]"/>
|
||||
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
|
||||
(0,0, {
|
||||
@@ -1981,6 +1993,10 @@
|
||||
'repartition_type': 'base',
|
||||
'minus_report_line_ids': [ref('l10n_fr.tax_report_04')],
|
||||
}),
|
||||
(0,0, {
|
||||
'factor_percent': 100,
|
||||
'repartition_type': 'tax',
|
||||
}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
@@ -1999,6 +2015,10 @@
|
||||
'repartition_type': 'base',
|
||||
'plus_report_line_ids': [ref('l10n_fr.tax_report_06')],
|
||||
}),
|
||||
(0,0, {
|
||||
'factor_percent': 100,
|
||||
'repartition_type': 'tax',
|
||||
}),
|
||||
]"/>
|
||||
<field name="refund_repartition_line_ids" eval="[(5, 0, 0),
|
||||
(0,0, {
|
||||
@@ -2006,6 +2026,10 @@
|
||||
'repartition_type': 'base',
|
||||
'minus_report_line_ids': [ref('l10n_fr.tax_report_06')],
|
||||
}),
|
||||
(0,0, {
|
||||
'factor_percent': 100,
|
||||
'repartition_type': 'tax',
|
||||
}),
|
||||
]"/>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ class ReportBomStructure(models.AbstractModel):
|
||||
qty = bom.product_uom_id._compute_quantity(qty, bom.product_tmpl_id.uom_id)
|
||||
for operation in bom.operation_ids:
|
||||
operation_cycle = float_round(qty / operation.workcenter_id.capacity, precision_rounding=1, rounding_method='UP')
|
||||
duration_expected = operation_cycle * (operation.time_cycle + (operation.workcenter_id.time_stop + operation.workcenter_id.time_start))
|
||||
duration_expected = (operation_cycle * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency) + (operation.workcenter_id.time_stop + operation.workcenter_id.time_start)
|
||||
total = ((duration_expected / 60.0) * operation.workcenter_id.costs_hour)
|
||||
operations.append({
|
||||
'level': level or 0,
|
||||
|
||||
@@ -510,9 +510,9 @@ class TestBoM(TestMrpCommon):
|
||||
# TEST CHEESE BOM STRUCTURE VALUE WITH BOM QUANTITY
|
||||
report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_cheese_cake.id, searchQty=60, searchVariant=False)
|
||||
#Operation time = 15 min * 60 + time_start + time_stop = 925
|
||||
self.assertEqual(report_values['lines']['operations_time'], 2400.0, 'Operation time should be the same for 1 unit or for the batch')
|
||||
# Operation cost is the sum of operation line : 10 min * 60 * 10€/hr = 100€ + 30min * 60 * 20€/hr = 700€
|
||||
self.assertEqual(float_compare(report_values['lines']['operations_cost'], 700, precision_digits=2), 0)
|
||||
self.assertEqual(report_values['lines']['operations_time'], 925.0, 'Operation time should be the same for 1 unit or for the batch')
|
||||
# Operation cost is the sum of operation line : (60 * 10)/60 * 10€ + (10 + 15 + 60 * 5)/60 * 20€ = 208,33€
|
||||
self.assertEqual(float_compare(report_values['lines']['operations_cost'], 208.33, precision_digits=2), 0)
|
||||
|
||||
for component_line in report_values['lines']['components']:
|
||||
# standard price * bom line quantity * current quantity / bom finished product quantity
|
||||
@@ -523,8 +523,8 @@ class TestBoM(TestMrpCommon):
|
||||
# 5.4 kg of crumble at the cost of a batch.
|
||||
crumble_cost = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_crumble.id, searchQty=5.4, searchVariant=False)['lines']['total']
|
||||
self.assertEqual(float_compare(component_line['total'], crumble_cost, precision_digits=2), 0)
|
||||
# total price = Cream (15.51€) + crumble_cost (34.63 €) + operation_cost(700€) = 750.14€
|
||||
self.assertEqual(float_compare(report_values['lines']['total'], 715.51 + crumble_cost, precision_digits=2), 0, 'Product Bom Price is not correct')
|
||||
# total price = Cream (15.51€) + crumble_cost (34.63 €) + operation_cost(208,33) = 258.47€
|
||||
self.assertEqual(float_compare(report_values['lines']['total'], 258.47, precision_digits=2), 0, 'Product Bom Price is not correct')
|
||||
|
||||
def test_bom_report_dozens(self):
|
||||
""" Simulate a drawer bom with dozens as bom units
|
||||
|
||||
@@ -125,7 +125,7 @@ class AccountMove(models.Model):
|
||||
vals = {
|
||||
'name': line.name[:64],
|
||||
'move_id': move.id,
|
||||
'partner_id': move.commercial_partner_id.id,
|
||||
'partner_id': line.partner_id.id or move.commercial_partner_id.id,
|
||||
'currency_id': line.currency_id.id,
|
||||
'product_id': line.product_id.id,
|
||||
'product_uom_id': line.product_uom_id.id,
|
||||
@@ -137,7 +137,6 @@ class AccountMove(models.Model):
|
||||
'analytic_tag_ids': [(6, 0, line.analytic_tag_ids.ids)],
|
||||
'exclude_from_invoice_tab': True,
|
||||
'is_anglo_saxon_line': True,
|
||||
'partner_id': line.partner_id.id,
|
||||
}
|
||||
vals.update(line._get_fields_onchange_subtotal(price_subtotal=vals['price_subtotal']))
|
||||
lines_vals_list.append(vals)
|
||||
@@ -146,7 +145,7 @@ class AccountMove(models.Model):
|
||||
vals = {
|
||||
'name': line.name[:64],
|
||||
'move_id': move.id,
|
||||
'partner_id': move.commercial_partner_id.id,
|
||||
'partner_id': line.partner_id.id or move.commercial_partner_id.id,
|
||||
'currency_id': line.currency_id.id,
|
||||
'product_id': line.product_id.id,
|
||||
'product_uom_id': line.product_uom_id.id,
|
||||
@@ -158,7 +157,6 @@ class AccountMove(models.Model):
|
||||
'analytic_tag_ids': [(6, 0, line.analytic_tag_ids.ids)],
|
||||
'exclude_from_invoice_tab': True,
|
||||
'is_anglo_saxon_line': True,
|
||||
'partner_id': line.partner_id.id,
|
||||
}
|
||||
vals.update(line._get_fields_onchange_subtotal(price_subtotal=vals['price_subtotal']))
|
||||
lines_vals_list.append(vals)
|
||||
|
||||
@@ -63,17 +63,15 @@ class SaleOrder(models.Model):
|
||||
action = {'type': 'ir.actions.act_window_close'}
|
||||
return action
|
||||
|
||||
def _create_invoices(self, grouped=False, final=False, start_date=None, end_date=None):
|
||||
""" Override the _create_invoice method in sale.order model in sale module
|
||||
Add new parameter in this method, to invoice sale.order with a date. This date is used in sale_make_invoice_advance_inv into this module.
|
||||
:param start_date: the start date of the period
|
||||
:param end_date: the end date of the period
|
||||
:return {account.move}: the invoices created
|
||||
def _create_invoices(self, grouped=False, final=False, date=None):
|
||||
"""Link timesheets to the created invoices. Date interval is injected in the
|
||||
context in sale_make_invoice_advance_inv wizard.
|
||||
"""
|
||||
moves = super(SaleOrder, self)._create_invoices(grouped, final)
|
||||
moves._link_timesheets_to_invoice(start_date, end_date)
|
||||
moves = super()._create_invoices(grouped=grouped, final=final, date=date)
|
||||
moves._link_timesheets_to_invoice(self.env.context.get("timesheet_start_date"), self.env.context.get("timesheet_end_date"))
|
||||
return moves
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = "sale.order.line"
|
||||
|
||||
|
||||
@@ -40,7 +40,10 @@ class SaleAdvancePaymentInv(models.TransientModel):
|
||||
if self.date_start_invoice_timesheet or self.date_end_invoice_timesheet:
|
||||
sale_orders.mapped('order_line')._recompute_qty_to_invoice(self.date_start_invoice_timesheet, self.date_end_invoice_timesheet)
|
||||
|
||||
sale_orders._create_invoices(final=self.deduct_down_payments, start_date=self.date_start_invoice_timesheet, end_date=self.date_end_invoice_timesheet)
|
||||
sale_orders.with_context(
|
||||
timesheet_start_date=self.date_start_invoice_timesheet,
|
||||
timesheet_end_date=self.date_end_invoice_timesheet
|
||||
)._create_invoices(final=self.deduct_down_payments)
|
||||
|
||||
if self._context.get('open_invoices', False):
|
||||
return sale_orders.action_view_invoice()
|
||||
|
||||
Reference in new issue
Block a user