# -*- coding: utf-8 -*- from odoo.tests.common import TransactionCase class TestIntegration(TransactionCase): """Integration tests for quality check lot preservation end-to-end workflows""" def setUp(self): super(TestIntegration, self).setUp() # Get model references self.StockMoveLine = self.env['stock.move.line'] self.QualityCheck = self.env['quality.check'] self.Product = self.env['product.product'] self.StockLocation = self.env['stock.location'] self.StockPicking = self.env['stock.picking'] self.StockPickingType = self.env['stock.picking.type'] self.StockMove = self.env['stock.move'] self.StockLot = self.env['stock.lot'] self.QualityPoint = self.env['quality.point'] self.Partner = self.env['res.partner'] # Create test product self.product = self.Product.create({ 'name': 'Test Product for Integration', 'type': 'consu', 'tracking': 'lot', }) # Get or create locations self.location_supplier = self.env.ref('stock.stock_location_suppliers') self.location_stock = self.env.ref('stock.stock_location_stock') # Get picking types self.picking_type_in = self.env.ref('stock.picking_type_in') # Create test supplier self.supplier = self.Partner.create({ 'name': 'Test Supplier', }) # Get or create a quality team self.quality_team = self.env['quality.alert.team'].search([], limit=1) if not self.quality_team: self.quality_team = self.env['quality.alert.team'].create({ 'name': 'Test Quality Team', }) # Get test type self.test_type = self.env.ref('quality_control.test_type_passfail', raise_if_not_found=False) if not self.test_type: self.test_type = self.env['quality.point.test_type'].create({ 'name': 'Pass/Fail Test', 'technical_name': 'passfail', }) # Create quality point for the product self.quality_point = self.QualityPoint.create({ 'product_ids': [(4, self.product.id)], 'picking_type_ids': [(4, self.picking_type_in.id)], 'test_type_id': self.test_type.id, 'team_id': self.quality_team.id, }) def _create_receipt_picking(self): """Helper to create a receipt picking""" return self.StockPicking.create({ 'picking_type_id': self.picking_type_in.id, 'location_id': self.location_supplier.id, 'location_dest_id': self.location_stock.id, 'partner_id': self.supplier.id, }) def _create_stock_move(self, picking, qty=1.0): """Helper to create a stock move""" return self.StockMove.create({ 'name': 'Test Move', 'product_id': self.product.id, 'product_uom_qty': qty, 'product_uom': self.product.uom_id.id, 'picking_id': picking.id, 'location_id': picking.location_id.id, 'location_dest_id': picking.location_dest_id.id, }) def _create_move_line(self, move, lot_id=False): """Helper to create a stock move line""" return self.StockMoveLine.create({ 'move_id': move.id, 'product_id': self.product.id, 'product_uom_id': self.product.uom_id.id, 'location_id': move.location_id.id, 'location_dest_id': move.location_dest_id.id, 'picking_id': move.picking_id.id, 'lot_id': lot_id, 'quantity': 1.0, }) def _create_lot(self, name): """Helper to create a lot""" return self.StockLot.create({ 'name': name, 'product_id': self.product.id, 'company_id': self.env.company.id, }) # Subtask 8.1: Create end-to-end receipt workflow test def test_end_to_end_receipt_workflow(self): """ End-to-end test: Create receipt, generate quality checks, complete quality checks before lot assignment, assign lot numbers, verify quality check states are preserved and lot numbers are copied. Requirements: 1.1, 2.1, 3.1 """ # Step 1: Create receipt picking receipt = self._create_receipt_picking() self.assertEqual(receipt.picking_type_id.code, 'incoming', "Picking should be a receipt operation") # Create stock move move = self._create_stock_move(receipt, qty=5.0) # Step 2: Confirm the picking and create move line receipt.action_confirm() # Create move line move_line = self._create_move_line(move) # Create quality check manually quality_check = self.QualityCheck.create({ 'product_id': self.product.id, 'picking_id': receipt.id, 'move_line_id': move_line.id, 'test_type_id': self.test_type.id, 'quality_state': 'none', 'team_id': self.quality_team.id, }) # Step 3: Complete quality checks before lot assignment initial_state = 'pass' quality_check.write({'quality_state': initial_state}) self.assertEqual(quality_check.quality_state, initial_state, "Quality check should be marked as pass") self.assertFalse(quality_check.lot_id, "Quality check should not have lot assigned yet") self.assertFalse(move_line.lot_id, "Move line should not have lot assigned yet") # Step 4: Assign lot numbers to stock move lines lot = self._create_lot('LOT-E2E-001') move_line.write({'lot_id': lot.id}) # Step 5: Verify quality check states are preserved self.assertEqual(quality_check.quality_state, initial_state, "Quality check state should be preserved after lot assignment") # Step 6: Verify lot numbers are copied to quality checks self.assertEqual(quality_check.lot_id.id, lot.id, "Lot number should be copied to quality check") # Additional verification: Ensure the relationship is intact self.assertEqual(quality_check.move_line_id.id, move_line.id, "Quality check should still be linked to move line") def test_end_to_end_receipt_workflow_with_fail_state(self): """ End-to-end test with quality check in 'fail' state. Verify fail state is preserved after lot assignment. Requirements: 1.1, 1.2, 2.1 """ # Create receipt picking receipt = self._create_receipt_picking() move = self._create_stock_move(receipt, qty=3.0) receipt.action_confirm() # Create move line move_line = self._create_move_line(move) # Create quality check and mark as fail quality_check = self.QualityCheck.create({ 'product_id': self.product.id, 'picking_id': receipt.id, 'move_line_id': move_line.id, 'test_type_id': self.test_type.id, 'quality_state': 'fail', 'team_id': self.quality_team.id, }) # Assign lot number lot = self._create_lot('LOT-E2E-FAIL-001') move_line.write({'lot_id': lot.id}) # Verify fail state is preserved self.assertEqual(quality_check.quality_state, 'fail', "Fail state should be preserved after lot assignment") self.assertEqual(quality_check.lot_id.id, lot.id, "Lot should be assigned to quality check") # Subtask 8.2: Create lot number change workflow test def test_lot_number_change_workflow(self): """ Test lot number change workflow: Create receipt with quality check and initial lot, change lot number on stock move line, verify quality check is updated with new lot, verify quality check state remains unchanged. Requirements: 3.1, 3.2 """ # Step 1: Create receipt with quality check and initial lot number receipt = self._create_receipt_picking() move = self._create_stock_move(receipt, qty=2.0) receipt.action_confirm() # Create move line move_line = self._create_move_line(move) # Create initial lot and assign it initial_lot = self._create_lot('LOT-CHANGE-INITIAL') move_line.write({'lot_id': initial_lot.id}) # Create quality check with pass state quality_check = self.QualityCheck.create({ 'product_id': self.product.id, 'picking_id': receipt.id, 'move_line_id': move_line.id, 'test_type_id': self.test_type.id, 'quality_state': 'pass', 'lot_id': initial_lot.id, 'team_id': self.quality_team.id, }) initial_state = quality_check.quality_state self.assertEqual(initial_state, 'pass', "Quality check should be in pass state") self.assertEqual(quality_check.lot_id.id, initial_lot.id, "Quality check should have initial lot") # Step 2: Change lot number on stock move line new_lot = self._create_lot('LOT-CHANGE-NEW') move_line.write({'lot_id': new_lot.id}) # Step 3: Verify quality check is updated with new lot number self.assertEqual(quality_check.lot_id.id, new_lot.id, "Quality check should be updated with new lot number") # Step 4: Verify quality check state remains unchanged self.assertEqual(quality_check.quality_state, initial_state, "Quality check state should remain unchanged after lot change") # Additional verification: Ensure the relationship is intact self.assertEqual(quality_check.move_line_id.id, move_line.id, "Quality check should still be linked to move line") def test_lot_number_change_workflow_multiple_changes(self): """ Test multiple lot number changes in sequence. Verify quality check is updated each time and state is preserved. Requirements: 3.1, 3.2 """ # Create receipt with quality check receipt = self._create_receipt_picking() move = self._create_stock_move(receipt, qty=1.0) receipt.action_confirm() # Create move line move_line = self._create_move_line(move) # Create quality check with fail state quality_check = self.QualityCheck.create({ 'product_id': self.product.id, 'picking_id': receipt.id, 'move_line_id': move_line.id, 'test_type_id': self.test_type.id, 'quality_state': 'fail', 'team_id': self.quality_team.id, }) initial_state = 'fail' # First lot assignment lot1 = self._create_lot('LOT-MULTI-CHANGE-001') move_line.write({'lot_id': lot1.id}) self.assertEqual(quality_check.lot_id.id, lot1.id, "Quality check should have first lot") self.assertEqual(quality_check.quality_state, initial_state, "State should be preserved after first change") # Second lot change lot2 = self._create_lot('LOT-MULTI-CHANGE-002') move_line.write({'lot_id': lot2.id}) self.assertEqual(quality_check.lot_id.id, lot2.id, "Quality check should have second lot") self.assertEqual(quality_check.quality_state, initial_state, "State should be preserved after second change") # Third lot change lot3 = self._create_lot('LOT-MULTI-CHANGE-003') move_line.write({'lot_id': lot3.id}) self.assertEqual(quality_check.lot_id.id, lot3.id, "Quality check should have third lot") self.assertEqual(quality_check.quality_state, initial_state, "State should be preserved after third change")