[PATCH] Upstream patch - 17112022

This commit is contained in:
Parthiv Patel committed 2022-11-17 08:34:57 +00:00
1 parent 984dc6d3f5
commit 4b67769126
7 files changed
+165 -58

No files matched your search

+19 -38
View File
@@ -43,60 +43,41 @@ class Partner(models.Model):
'member_lines.account_invoice_line.move_id.partner_id',
'free_member',
'member_lines.date_to', 'member_lines.date_from',
'associate_member')
'associate_member', 'associate_member.membership_state')
def _compute_membership_state(self):
today = fields.Date.today()
for partner in self:
state = 'none'
partner.membership_start = self.env['membership.membership_line'].search([
('partner', '=', partner.associate_member.id or partner.id), ('date_cancel','=',False)
('partner', '=', partner.associate_member.id or partner.id), ('date_cancel', '=', False)
], limit=1, order='date_from').date_from
partner.membership_stop = self.env['membership.membership_line'].search([
('partner', '=', partner.associate_member.id or partner.id),('date_cancel','=',False)
('partner', '=', partner.associate_member.id or partner.id), ('date_cancel', '=', False)
], limit=1, order='date_to desc').date_to
partner.membership_cancel = self.env['membership.membership_line'].search([
('partner', '=', partner.id)
], limit=1, order='date_cancel').date_cancel
if partner.membership_cancel and today > partner.membership_cancel:
partner.membership_state = 'free' if partner.free_member else 'canceled'
continue
if partner.membership_stop and today > partner.membership_stop:
if partner.free_member:
partner.membership_state = 'free'
continue
if partner.associate_member:
partner.associate_member._compute_membership_state()
partner.membership_state = partner.associate_member.membership_state
continue
line_states = [mline.state for mline in partner.member_lines if \
(mline.date_to or date.min) >= today and \
(mline.date_from or date.min) <= today and \
mline.account_invoice_line.move_id.partner_id == partner]
if partner.free_member and partner.membership_state != 'paid':
partner.membership_state = 'free'
continue
if 'paid' in line_states:
state = 'paid'
elif 'invoiced' in line_states:
state = 'invoiced'
elif 'waiting' in line_states:
state = 'waiting'
elif 'canceled' in line_states:
state = 'canceled'
if state == 'none':
for mline in partner.member_lines:
# if there is an old invoice paid, set the state to 'old'
if ((mline.date_from or date.min) < today and (mline.date_to or date.min) < today and \
(mline.date_from or date.min) <= (mline.date_to or date.min) and \
mline.account_invoice_id and mline.account_invoice_id.payment_state in ('in_payment', 'paid')):
state = 'old'
break
if partner.free_member and state != 'paid':
state = 'free'
partner.membership_state = state
for mline in partner.member_lines:
if (mline.date_to or date.min) >= today and (mline.date_from or date.min) <= today:
partner.membership_state = mline.state
break
elif ((mline.date_from or date.min) < today and (mline.date_to or date.min) <= today and \
(mline.date_from or date.min) < (mline.date_to or date.min)):
if mline.account_invoice_id and mline.account_invoice_id.payment_state in ('in_payment', 'paid'):
partner.membership_state = 'old'
elif mline.account_invoice_id and mline.account_invoice_id.state == 'cancel':
partner.membership_state = 'canceled'
break
else:
partner.membership_state = 'none'
@api.constrains('associate_member')
def _check_recursion_associate_member(self):
+19 -5
View File
@@ -693,20 +693,28 @@ class MrpProduction(models.Model):
@api.onchange('lot_producing_id')
def _onchange_lot_producing(self):
if self.product_id.tracking == 'serial':
res = self._can_produce_serial_number()
if res is not True:
return res
def _can_produce_serial_number(self, sn=None):
self.ensure_one()
sn = sn or self.lot_producing_id
if self.product_id.tracking == 'serial' and sn:
if self.env['stock.move.line'].search([
('lot_id', '=', self.lot_producing_id.id),
('lot_id', '=', sn.id),
('qty_done', '=', 1),
('state', '=', 'done'),
('location_id.usage', '!=', 'production'),
('location_dest_id.usage', '!=', 'production'),
], limit=1) or self._is_finished_sn_already_produced(self.lot_producing_id):
], limit=1) or self._is_finished_sn_already_produced(sn):
return {
'warning': {
'title': _('Warning'),
'message': _('Existing Serial number (%s). Please correct the serial numbers encoded.') % self.lot_producing_id.name
'message': _('Serial number (%s) has already been produced.') % sn.name,
}
}
return True
@api.onchange('bom_id')
def _onchange_workorder_ids(self):
@@ -1787,8 +1795,14 @@ class MrpProduction(models.Model):
('state', '=', 'done'),
('location_dest_id.scrap_location', '=', True)
])
unremoved = self.env['stock.move.line'].search_count([
('lot_id', '=', move_line.lot_id.id),
('state', '=', 'done'),
('location_id.scrap_location', '=', True),
('location_dest_id.scrap_location', '=', False),
])
# Either removed or unbuild
if not ((duplicates_returned or removed) and duplicates - duplicates_returned - removed == 0):
if not ((duplicates_returned or removed) and duplicates - duplicates_returned - removed + unremoved == 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
+8 -10
View File
@@ -407,6 +407,12 @@ class MrpWorkorder(models.Model):
def _onchange_expected_duration(self):
self.duration_expected = self._get_duration_expected()
@api.onchange('finished_lot_id')
def _onchange_finished_lot_id(self):
res = self.production_id._can_produce_serial_number(sn=self.finished_lot_id)
if res is not True:
return res
def write(self, values):
if 'production_id' in values:
raise UserError(_('You cannot link this work order to another manufacturing order.'))
@@ -847,16 +853,8 @@ class MrpWorkorder(models.Model):
)
def _check_sn_uniqueness(self):
""" Alert the user if the serial number as already been produced """
if self.product_tracking == 'serial' and self.finished_lot_id:
sml = self.env['stock.move.line'].search_count([
('lot_id', '=', self.finished_lot_id.id),
('location_id.usage', '=', 'production'),
('qty_done', '=', 1),
('state', '=', 'done')
])
if sml:
raise UserError(_('This serial number for product %s has already been produced', self.product_id.name))
# todo master: remove
pass
def _update_qty_producing(self, quantity):
self.ensure_one()
+87
View File
@@ -497,3 +497,90 @@ class TestTraceability(TestMrpCommon):
mo.button_mark_done()
self.assertEqual(mo.state, 'done')
def test_unbuild_scrap_and_unscrap_tracked_component(self):
"""
Suppose a tracked-by-SN component C. There is one C in stock with SN01.
Build a product P that uses C with SN, unbuild P, scrap SN, unscrap SN
and rebuild a product with SN in the components
"""
warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
stock_location = warehouse.lot_stock_id
component = self.bom_4.bom_line_ids.product_id
component.write({
'type': 'product',
'tracking': 'serial',
})
serial_number = self.env['stock.production.lot'].create({
'product_id': component.id,
'name': 'Super Serial',
'company_id': self.env.company.id,
})
self.env['stock.quant']._update_available_quantity(component, stock_location, 1, lot_id=serial_number)
# produce 1
mo_form = Form(self.env['mrp.production'])
mo_form.bom_id = self.bom_4
mo = mo_form.save()
mo.action_confirm()
mo.action_assign()
self.assertEqual(mo.move_raw_ids.move_line_ids.lot_id, serial_number)
with Form(mo) as mo_form:
mo_form.qty_producing = 1
mo.move_raw_ids.move_line_ids.qty_done = 1
mo.button_mark_done()
# unbuild
action = mo.button_unbuild()
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
wizard.action_validate()
# scrap the component
scrap = self.env['stock.scrap'].create({
'product_id': component.id,
'product_uom_id': component.uom_id.id,
'scrap_qty': 1,
'lot_id': serial_number.id,
})
scrap_location = scrap.scrap_location_id
scrap.do_scrap()
# unscrap the component
internal_move = self.env['stock.move'].create({
'name': component.name,
'location_id': scrap_location.id,
'location_dest_id': stock_location.id,
'product_id': component.id,
'product_uom': component.uom_id.id,
'product_uom_qty': 1.0,
'move_line_ids': [(0, 0, {
'product_id': component.id,
'location_id': scrap_location.id,
'location_dest_id': stock_location.id,
'product_uom_id': component.uom_id.id,
'qty_done': 1.0,
'lot_id': serial_number.id,
})],
})
internal_move._action_confirm()
internal_move._action_done()
# produce one with the unscrapped component
mo_form = Form(self.env['mrp.production'])
mo_form.bom_id = self.bom_4
mo = mo_form.save()
mo.action_confirm()
mo.action_assign()
self.assertEqual(mo.move_raw_ids.move_line_ids.lot_id, serial_number)
with Form(mo) as mo_form:
mo_form.qty_producing = 1
mo.move_raw_ids.move_line_ids.qty_done = 1
mo.button_mark_done()
self.assertRecordValues((mo.move_finished_ids + mo.move_raw_ids).move_line_ids, [
{'product_id': self.bom_4.product_id.id, 'lot_id': False, 'qty_done': 1},
{'product_id': component.id, 'lot_id': serial_number.id, 'qty_done': 1},
])
+6 -5
View File
@@ -50,15 +50,16 @@ class Rating(http.Controller):
'rate_names': rate_names, 'rate': rate
})
@http.route(['/rate/<string:token>/submit_feedback'], type="http", auth="public", methods=['post'], website=True)
@http.route(['/rate/<string:token>/submit_feedback'], type="http", auth="public", methods=['post', 'get'], website=True)
def action_submit_rating(self, token, **kwargs):
rate = int(kwargs.get('rate'))
assert rate in (1, 3, 5), "Incorrect rating"
rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)])
if not rating:
return request.not_found()
record_sudo = request.env[rating.res_model].sudo().browse(rating.res_id)
record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback'))
if request.httprequest.method == "POST":
rate = int(kwargs.get('rate'))
assert rate in (1, 3, 5), "Incorrect rating"
record_sudo = request.env[rating.res_model].sudo().browse(rating.res_id)
record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback'))
lang = rating.partner_id.lang or get_lang(request.env).code
return request.env['ir.ui.view'].with_context(lang=lang)._render_template('rating.rating_external_page_view', {
'web_base_url': request.env['ir.config_parameter'].sudo().get_param('web.base.url'),
+1
View File
@@ -2,3 +2,4 @@
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import test_security
from . import test_controller
+25
View File
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra.tests import HttpCase, tagged, new_test_user
@tagged('post_install', '-at_install')
class TestControllersRoute(HttpCase):
def setUp(self):
super(TestControllersRoute, self).setUp()
self.user = new_test_user(self.env, "test_user_1", email="test_user_1@nowhere.com", tz="UTC")
self.partner = self.user.partner_id
def test_controller_rating(self):
rating_test = self.env['rating.rating'].with_user(self.user).create({
'res_model_id': self.env['ir.model'].sudo().search([('model', '=', 'res.partner')], limit=1).id,
'res_model': 'res.partner',
'res_id': self.partner.id,
'rating': 3
})
self.authenticate(None, None)
access_token = rating_test.access_token
url = '/rate/%s/submit_feedback' % access_token
req = self.url_open(url)
self.assertEqual(req.status_code, 200, "Response should = OK")