def test_shipping_cost_numbers(self):
        # Free delivery should not be taken into account when checking for minimum required threshold
        p_minimum_threshold_free_delivery = self.env[
            'sale.coupon.program'].create({
                'name': 'free shipping if > 872 tax exl',
                'promo_code_usage': 'code_needed',
                'promo_code': 'free_shipping',
                'reward_type': 'free_shipping',
                'program_type': 'promotion_program',
                'rule_minimum_amount': 872,
            })
        self.p2 = self.env['sale.coupon.program'].create({
            'name':
            'Buy 4 large cabinet, get one for free',
            'promo_code_usage':
            'no_code_needed',
            'reward_type':
            'product',
            'program_type':
            'promotion_program',
            'reward_product_id':
            self.iPadMini.id,
            'rule_min_quantity':
            3,
            'rule_products_domain':
            '[["name","ilike","large cabinet"]]',
        })
        order = self.empty_order
        self.iPadMini.taxes_id = self.tax_10pc_incl
        sol1 = self.env['sale.order.line'].create({
            'product_id': self.iPadMini.id,
            'name': 'Large Cabinet',
            'product_uom_qty': 3.0,
            'order_id': order.id,
        })

        # I add delivery cost in Sales order
        delivery_wizard = Form(
            self.env['choose.delivery.carrier'].with_context({
                'default_order_id':
                order.id,
                'default_carrier_id':
                self.carrier.id
            }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()
        order.recompute_coupon_lines()
        self.assertEqual(len(order.order_line.ids), 2)
        self.assertEqual(order.reward_amount, 0)
        # Shipping is 20 + 15%tax
        self.assertEqual(
            sum([
                line.price_total
                for line in order._get_no_effect_on_threshold_lines()
            ]), 23)
        self.assertEqual(order.amount_untaxed, 872.73 + 20)

        self.env['sale.coupon.apply.code'].sudo().apply_coupon(
            order, 'free_shipping')
        order.recompute_coupon_lines()
        self.assertEqual(
            len(order.order_line.ids), 3,
            "We should get the delivery line and the free delivery since we are below 872.73$ with the 10% discount"
        )
        self.assertEqual(order.reward_amount, -20)
        self.assertEqual(
            sum([
                line.price_total
                for line in order._get_no_effect_on_threshold_lines()
            ]), 0)
        self.assertEqual(order.amount_untaxed, 872.73)

        sol1.product_uom_qty = 4
        order.recompute_coupon_lines()
        self.assertEqual(len(order.order_line.ids), 4,
                         "We should get a free Large Cabinet")
        self.assertEqual(order.reward_amount, -20 - 290.91)
        self.assertEqual(
            sum([
                line.price_total
                for line in order._get_no_effect_on_threshold_lines()
            ]), 0)
        self.assertEqual(order.amount_untaxed, 872.73)

        p_specific_product = self.env['sale.coupon.program'].create({
            'name':
            '20% reduction on large cabinet in cart',
            'promo_code_usage':
            'no_code_needed',
            'reward_type':
            'discount',
            'program_type':
            'promotion_program',
            'discount_type':
            'percentage',
            'discount_percentage':
            20.0,
            'discount_apply_on':
            'cheapest_product',
        })
        p_specific_product.discount_apply_on = 'cheapest_product'
        order.recompute_coupon_lines()
        # 872.73 - (20% of 1 iPad) = 872.73 - 58.18 = 814.55
        self.assertAlmostEqual(
            order.amount_untaxed, 814.55, 2,
            "One large cabinet should be discounted by 20%")
Exemple #2
0
    def test_22_bom_report_recursive_bom(self):
        """ Test report with recursive BoM and different quantities.
        BoM 1:
        product = Finished (units)
        quantity = 100 units
        - Semi-Finished 5 kg

        BoM 2:
        product = Semi-Finished (kg)
        quantity = 11 kg
        - Assembly 2 dozens

        BoM 3:
        product = Assembly (dozens)
        quantity = 5 dozens
        - Raw Material 4 litres (product.product 5$/litre)

        Check the Price for 80 units of Finished -> 2.92$:
        """
        # Create a products templates
        uom_unit = self.env.ref('uom.product_uom_unit')
        uom_kg = self.env.ref('uom.product_uom_kgm')
        uom_dozen = self.env.ref('uom.product_uom_dozen')
        uom_litre = self.env.ref('uom.product_uom_litre')

        finished = self.env['product.product'].create({
            'name': 'Finished',
            'type': 'product',
            'uom_id': uom_unit.id,
            'uom_po_id': uom_unit.id,
        })

        semi_finished = self.env['product.product'].create({
            'name': 'Semi-Finished',
            'type': 'product',
            'uom_id': uom_kg.id,
            'uom_po_id': uom_kg.id,
        })

        assembly = self.env['product.product'].create({
            'name': 'Assembly',
            'type': 'product',
            'uom_id': uom_dozen.id,
            'uom_po_id': uom_dozen.id,
        })

        raw_material = self.env['product.product'].create({
            'name': 'Raw Material',
            'type': 'product',
            'uom_id': uom_litre.id,
            'uom_po_id': uom_litre.id,
            'standard_price': 5,
        })

        #Create bom
        bom_finished = Form(self.env['mrp.bom'])
        bom_finished.product_tmpl_id = finished.product_tmpl_id
        bom_finished.product_qty = 100
        with bom_finished.bom_line_ids.new() as line:
            line.product_id = semi_finished
            line.product_uom_id = uom_kg
            line.product_qty = 5
        bom_finished = bom_finished.save()

        bom_semi_finished = Form(self.env['mrp.bom'])
        bom_semi_finished.product_tmpl_id = semi_finished.product_tmpl_id
        bom_semi_finished.product_qty = 11
        with bom_semi_finished.bom_line_ids.new() as line:
            line.product_id = assembly
            line.product_uom_id = uom_dozen
            line.product_qty = 2
        bom_semi_finished = bom_semi_finished.save()

        bom_assembly = Form(self.env['mrp.bom'])
        bom_assembly.product_tmpl_id = assembly.product_tmpl_id
        bom_assembly.product_qty = 5
        with bom_assembly.bom_line_ids.new() as line:
            line.product_id = raw_material
            line.product_uom_id = uom_litre
            line.product_qty = 4
        bom_assembly = bom_assembly.save()

        report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_finished.id, searchQty=80)

        self.assertAlmostEqual(report_values['lines']['total'], 2.92)
    def test_01_delivery_stock_move(self):
        # Test if the stored fields of stock moves are computed with invoice before delivery flow
        self.sale_prepaid = self.SaleOrder.create({
            'partner_id':
            self.partner_18.id,
            'partner_invoice_id':
            self.partner_18.id,
            'partner_shipping_id':
            self.partner_18.id,
            'pricelist_id':
            self.pricelist_id.id,
            'order_line': [(0, 0, {
                'name': 'Cable Management Box',
                'product_id': self.product_cable_management_box.id,
                'product_uom_qty': 2,
                'product_uom': self.product_uom_unit.id,
                'price_unit': 750.00,
            })],
        })

        # I add delivery cost in Sales order
        delivery_wizard = Form(
            self.env['choose.delivery.carrier'].with_context({
                'default_order_id':
                self.sale_prepaid.id,
                'default_carrier_id':
                self.normal_delivery.id,
            }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()

        # I confirm the SO.
        self.sale_prepaid.action_confirm()
        self.sale_prepaid._create_invoices()

        # I check that the invoice was created
        self.assertEqual(len(self.sale_prepaid.invoice_ids), 1,
                         "Invoice not created.")

        # I confirm the invoice

        self.invoice = self.sale_prepaid.invoice_ids
        self.invoice.action_post()

        # I pay the invoice.
        self.journal = self.AccountJournal.search(
            [('type', '=', 'cash'),
             ('company_id', '=', self.sale_prepaid.company_id.id)],
            limit=1)

        register_payments = self.env['account.payment.register'].with_context(
            active_model='account.move', active_ids=self.invoice.ids).create({
                'journal_id':
                self.journal.id,
            })
        register_payments._create_payments()

        # Check the SO after paying the invoice
        self.assertNotEqual(self.sale_prepaid.invoice_count, 0,
                            'order not invoiced')
        self.assertTrue(self.sale_prepaid.invoice_status == 'invoiced',
                        'order is not invoiced')
        self.assertEqual(len(self.sale_prepaid.picking_ids), 1,
                         'pickings not generated')

        # Check the stock moves
        moves = self.sale_prepaid.picking_ids.move_ids
        self.assertEqual(moves[0].product_qty, 2, 'wrong product_qty')
        self.assertEqual(moves[0].weight, 2.0, 'wrong move weight')

        # Ship
        moves.move_line_ids.write({'qty_done': 2})
        self.picking = self.sale_prepaid.picking_ids._action_done()
        self.assertEqual(moves[0].move_line_ids.sale_price, 1725.0,
                         'wrong shipping value')
Exemple #4
0
    def test_qty_invoiced(self):
        """Verify uom rounding is correctly considered during qty_invoiced compute"""
        sale_order = self.env['sale.order'].with_context(
            tracking_disable=True).create({
                'partner_id':
                self.partner_a.id,
                'partner_invoice_id':
                self.partner_a.id,
                'partner_shipping_id':
                self.partner_a.id,
                'pricelist_id':
                self.company_data['default_pricelist'].id,
            })

        SaleOrderLine = self.env['sale.order.line'].with_context(
            tracking_disable=True)
        sol_prod_deliver = SaleOrderLine.create({
            'product_id':
            self.company_data['product_order_no'].id,
            'product_uom_qty':
            5,
            'order_id':
            sale_order.id,
            'tax_id':
            False,
        })

        # Confirm the SO
        sale_order.action_confirm()

        sol_prod_deliver.write({'qty_delivered': 5.0})
        # Context
        self.context = {
            'active_model': 'sale.order',
            'active_ids': [sale_order.id],
            'active_id': sale_order.id,
            'default_journal_id': self.company_data['default_journal_sale'].id,
        }

        # Let's do an invoice with invoiceable lines
        invoicing_wizard = self.env['sale.advance.payment.inv'].with_context(
            self.context).create({'advance_payment_method': 'delivered'})
        invoicing_wizard.create_invoices()

        self.assertEqual(sol_prod_deliver.qty_invoiced, 5.0)
        # We would have to change the digits of the field to
        # test a greater decimal precision.
        quantity = 5.13
        move_form = Form(sale_order.invoice_ids)
        with move_form.invoice_line_ids.edit(0) as line_form:
            line_form.quantity = quantity
        move_form.save()

        # Default uom rounding to 0.01
        qty_invoiced_field = sol_prod_deliver._fields.get('qty_invoiced')
        sol_prod_deliver.env.add_to_compute(qty_invoiced_field,
                                            sol_prod_deliver)
        self.assertEqual(sol_prod_deliver.qty_invoiced, quantity)

        # Rounding to 0.1, should be rounded with UP (ceil) rounding_method
        # Not floor or half up rounding.
        sol_prod_deliver.product_uom.rounding *= 10
        sol_prod_deliver.product_uom.flush(['rounding'])
        expected_qty = 5.2
        qty_invoiced_field = sol_prod_deliver._fields.get('qty_invoiced')
        sol_prod_deliver.env.add_to_compute(qty_invoiced_field,
                                            sol_prod_deliver)
        self.assertEqual(sol_prod_deliver.qty_invoiced, expected_qty)
Exemple #5
0
    def test_20_bom_report(self):
        """ Simulate a crumble receipt with mrp and open the bom structure
        report and check that data insde are correct.
        """
        uom_kg = self.env.ref('uom.product_uom_kgm')
        uom_litre = self.env.ref('uom.product_uom_litre')
        crumble = self.env['product.product'].create({
            'name': 'Crumble',
            'type': 'product',
            'uom_id': uom_kg.id,
            'uom_po_id': uom_kg.id,
        })
        butter = self.env['product.product'].create({
            'name': 'Butter',
            'type': 'product',
            'uom_id': uom_kg.id,
            'uom_po_id': uom_kg.id,
            'standard_price': 7.01
        })
        biscuit = self.env['product.product'].create({
            'name': 'Biscuit',
            'type': 'product',
            'uom_id': uom_kg.id,
            'uom_po_id': uom_kg.id,
            'standard_price': 1.5
        })
        bom_form_crumble = Form(self.env['mrp.bom'])
        bom_form_crumble.product_tmpl_id = crumble.product_tmpl_id
        bom_form_crumble.product_qty = 11
        bom_form_crumble.product_uom_id = uom_kg
        bom_crumble = bom_form_crumble.save()

        workcenter = self.env['mrp.workcenter'].create({
            'costs_hour': 10,
            'name': 'Deserts Table'
        })

        operation_1 = self.env['mrp.routing.workcenter'].create({
            'workcenter_id': workcenter.id,
            'name': 'Prepare biscuits',
            'time_cycle_manual': 5,
            'bom_id': bom_crumble.id
        })

        operation_2 = self.env['mrp.routing.workcenter'].create({
            'workcenter_id': workcenter.id,
            'name': 'Prepare butter',
            'time_cycle_manual': 3,
            'bom_id': bom_crumble.id
        })

        operation_3 = self.env['mrp.routing.workcenter'].create({
            'workcenter_id': workcenter.id,
            'name': 'Mix manually',
            'time_cycle_manual': 5,
            'bom_id': bom_crumble.id
        })

        with Form(bom_crumble) as bom:
            with bom.bom_line_ids.new() as line:
                line.product_id = butter
                line.product_uom_id = uom_kg
                line.product_qty = 5
            with bom.bom_line_ids.new() as line:
                line.product_id = biscuit
                line.product_uom_id = uom_kg
                line.product_qty = 6
            bom.operation_ids.add(operation_1)
            bom.operation_ids.add(operation_2)
            bom.operation_ids.add(operation_3)

        # TEST BOM STRUCTURE VALUE WITH BOM QUANTITY
        report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_crumble.id, searchQty=11, searchVariant=False)
        # 5 min 'Prepare biscuits' + 3 min 'Prepare butter' + 5 min 'Mix manually' = 13 minutes
        self.assertEqual(report_values['lines']['operations_time'], 13.0, 'Operation time should be the same for 1 unit or for the batch')
        # Operation cost is the sum of operation line.
        operation_cost = float_round(5 / 60 * 10, precision_digits=2) * 2 + float_round(3 / 60 * 10, precision_digits=2)
        self.assertEqual(float_compare(report_values['lines']['operations_cost'], operation_cost, precision_digits=2), 0, '13 minute for 10$/hours -> 2.16')

        for component_line in report_values['lines']['components']:
            # standard price * bom line quantity * current quantity / bom finished product quantity
            if component_line['prod_id'] == butter.id:
                # 5 kg of butter at 7.01$ for 11kg of crumble -> 35.05$
                self.assertEqual(float_compare(component_line['total'], (7.01 * 5), precision_digits=2), 0)
            if component_line['prod_id'] == biscuit.id:
                # 6 kg of biscuits at 1.50$ for 11kg of crumble -> 9$
                self.assertEqual(float_compare(component_line['total'], (1.5 * 6), precision_digits=2), 0)
        # total price = 35.05 + 9 + operation_cost(0.83 + 0.83 + 0.5 = 2.16) = 46,21
        self.assertEqual(float_compare(report_values['lines']['total'], 46.21, precision_digits=2), 0, 'Product Bom Price is not correct')
        self.assertEqual(float_compare(report_values['lines']['total'] / 11.0, 4.20, precision_digits=2), 0, 'Product Unit Bom Price is not correct')

        # TEST BOM STRUCTURE VALUE BY UNIT
        report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_crumble.id, searchQty=1, searchVariant=False)
        # 5 min 'Prepare biscuits' + 3 min 'Prepare butter' + 5 min 'Mix manually' = 13 minutes
        self.assertEqual(report_values['lines']['operations_time'], 13.0, 'Operation time should be the same for 1 unit or for the batch')
        # Operation cost is the sum of operation line.
        operation_cost = float_round(5 / 60 * 10, precision_digits=2) * 2 + float_round(3 / 60 * 10, precision_digits=2)
        self.assertEqual(float_compare(report_values['lines']['operations_cost'], operation_cost, precision_digits=2), 0, '13 minute for 10$/hours -> 2.16')

        for component_line in report_values['lines']['components']:
            # standard price * bom line quantity * current quantity / bom finished product quantity
            if component_line['prod_id'] == butter.id:
                # 5 kg of butter at 7.01$ for 11kg of crumble -> / 11 for price per unit (3.19)
                self.assertEqual(float_compare(component_line['total'], (7.01 * 5) * (1 / 11), precision_digits=2), 0)
            if component_line['prod_id'] == biscuit.id:
                # 6 kg of biscuits at 1.50$ for 11kg of crumble -> / 11 for price per unit (0.82)
                self.assertEqual(float_compare(component_line['total'], (1.5 * 6) * (1 / 11), precision_digits=2), 0)
        # total price = 3.19 + 0.82 + operation_cost(0.83 + 0.83 + 0.5 = 2.16) = 6,17
        self.assertEqual(float_compare(report_values['lines']['total'], 6.17, precision_digits=2), 0, 'Product Unit Bom Price is not correct')

        # TEST OPERATION COST WHEN PRODUCED QTY > BOM QUANTITY
        report_values_12 = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_crumble.id, searchQty=12, searchVariant=False)
        report_values_22 = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_crumble.id, searchQty=22, searchVariant=False)
        operation_cost = float_round(10 / 60 * 10, precision_digits=2) * 2 + float_round(6 / 60 * 10, precision_digits=2)
        # Both needs 2 operation cycle
        self.assertEqual(report_values_12['lines']['operations_cost'], report_values_22['lines']['operations_cost'])
        self.assertEqual(report_values_22['lines']['operations_cost'], operation_cost)
        report_values_23 = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_crumble.id, searchQty=23, searchVariant=False)
        operation_cost = float_round(15 / 60 * 10, precision_digits=2) * 2 + float_round(9 / 60 * 10, precision_digits=2)
        self.assertEqual(report_values_23['lines']['operations_cost'], operation_cost)

        # Create a more complex BoM with a sub product
        cheese_cake = self.env['product.product'].create({
            'name': 'Cheese Cake 300g',
            'type': 'product',
        })
        cream = self.env['product.product'].create({
            'name': 'cream',
            'type': 'product',
            'uom_id': uom_litre.id,
            'uom_po_id': uom_litre.id,
            'standard_price': 5.17,
        })
        bom_form_cheese_cake = Form(self.env['mrp.bom'])
        bom_form_cheese_cake.product_tmpl_id = cheese_cake.product_tmpl_id
        bom_form_cheese_cake.product_qty = 60
        bom_form_cheese_cake.product_uom_id = self.uom_unit
        bom_cheese_cake = bom_form_cheese_cake.save()

        workcenter_2 = self.env['mrp.workcenter'].create({
            'name': 'cake mounting',
            'costs_hour': 20,
            'time_start': 10,
            'time_stop': 15
        })

        operation_4 = self.env['mrp.routing.workcenter'].create({
            'workcenter_id': workcenter.id,
            'name': 'Mix cheese and crumble',
            'time_cycle_manual': 10,
            'bom_id': bom_cheese_cake.id
        })

        operation_5 = self.env['mrp.routing.workcenter'].create({
            'workcenter_id': workcenter_2.id,
            'name': 'Cake mounting',
            'time_cycle_manual': 5,
            'bom_id': bom_cheese_cake.id
        })

        with Form(bom_cheese_cake) as bom:
            with bom.bom_line_ids.new() as line:
                line.product_id = cream
                line.product_uom_id = uom_litre
                line.product_qty = 3
            with bom.bom_line_ids.new() as line:
                line.product_id = crumble
                line.product_uom_id = uom_kg
                line.product_qty = 5.4
            bom.operation_ids.add(operation_4)
            bom.operation_ids.add(operation_5)


        # 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)
        self.assertEqual(report_values['lines']['operations_time'], 40.0, 'Operation time should be the same for 1 unit or for the batch')
        # Operation cost is the sum of operation line.
        operation_cost = float_round(10 / 60 * 10, precision_digits=2) + float_round(30 / 60 * 20, precision_digits=2)
        self.assertEqual(float_compare(report_values['lines']['operations_cost'], operation_cost, precision_digits=2), 0)

        for component_line in report_values['lines']['components']:
            # standard price * bom line quantity * current quantity / bom finished product quantity
            if component_line['prod_id'] == cream.id:
                # 3 liter of cream at 5.17$ for 60 unit of cheese cake -> 15.51$
                self.assertEqual(float_compare(component_line['total'], (3 * 5.17), precision_digits=2), 0)
            if component_line['prod_id'] == crumble.id:
                # 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 = 15.51 + crumble_cost + operation_cost(10 + 1.67 = 11.67) = 27.18 + crumble_cost
        self.assertEqual(float_compare(report_values['lines']['total'], 27.18 + crumble_cost, precision_digits=2), 0, 'Product Bom Price is not correct')
Exemple #6
0
    def test_toggle_active_warehouse_1(self):
        """ Basic test that create a warehouse with classic configuration.
        Archive it and check that locations, picking types, routes, rules are
        correclty active or archive.
        """
        wh = Form(self.env['stock.warehouse'])
        wh.name = "The attic of Willy"
        wh.code = "WIL"
        warehouse = wh.save()

        custom_location = Form(self.env['stock.location'])
        custom_location.name = "A Trunk"
        custom_location.location_id = warehouse.lot_stock_id
        custom_location = custom_location.save()

        # Archive warehouse
        warehouse.toggle_active()
        # Global rule
        self.assertFalse(warehouse.mto_pull_id.active)

        # Route
        self.assertFalse(warehouse.reception_route_id.active)
        self.assertFalse(warehouse.delivery_route_id.active)

        # Location
        self.assertFalse(warehouse.lot_stock_id.active)
        self.assertFalse(warehouse.wh_input_stock_loc_id.active)
        self.assertFalse(warehouse.wh_qc_stock_loc_id.active)
        self.assertFalse(warehouse.wh_output_stock_loc_id.active)
        self.assertFalse(warehouse.wh_pack_stock_loc_id.active)
        self.assertFalse(custom_location.active)

        # Picking Type
        self.assertFalse(warehouse.in_type_id.active)
        self.assertFalse(warehouse.out_type_id.active)
        self.assertFalse(warehouse.int_type_id.active)
        self.assertFalse(warehouse.pick_type_id.active)
        self.assertFalse(warehouse.pack_type_id.active)

        # Active warehouse
        warehouse.toggle_active()
        # Global rule
        self.assertTrue(warehouse.mto_pull_id.active)

        # Route
        self.assertTrue(warehouse.reception_route_id.active)
        self.assertTrue(warehouse.delivery_route_id.active)

        # Location
        self.assertTrue(warehouse.lot_stock_id.active)
        self.assertFalse(warehouse.wh_input_stock_loc_id.active)
        self.assertFalse(warehouse.wh_qc_stock_loc_id.active)
        self.assertFalse(warehouse.wh_output_stock_loc_id.active)
        self.assertFalse(warehouse.wh_pack_stock_loc_id.active)
        self.assertTrue(custom_location.active)

        # Picking Type
        self.assertTrue(warehouse.in_type_id.active)
        self.assertTrue(warehouse.out_type_id.active)
        self.assertTrue(warehouse.int_type_id.active)
        self.assertFalse(warehouse.pick_type_id.active)
        self.assertFalse(warehouse.pack_type_id.active)
    def test_landed_cost_on_mrp(self):
        # Initial inventory
        quants = self.env['stock.quant'].with_context(
            inventory_mode=True).create({
                'product_id':
                self.product_component1.id,
                'inventory_quantity':
                500,
                'location_id':
                self.warehouse_1.lot_stock_id.id,
            })
        quants |= self.env['stock.quant'].with_context(
            inventory_mode=True).create({
                'product_id':
                self.product_component2.id,
                'inventory_quantity':
                500,
                'location_id':
                self.warehouse_1.lot_stock_id.id,
            })
        quants.action_apply_inventory()

        man_order_form = Form(self.env['mrp.production'].with_user(
            self.allow_user))
        man_order_form.product_id = self.product_refrigerator
        man_order_form.bom_id = self.bom_refri
        man_order_form.product_qty = 2.0
        man_order = man_order_form.save()

        self.assertEqual(man_order.state, 'draft',
                         "Production order should be in draft state.")
        man_order.action_confirm()
        self.assertEqual(man_order.state, 'confirmed',
                         "Production order should be in confirmed state.")

        # check production move
        production_move = man_order.move_finished_ids
        self.assertEqual(production_move.product_id, self.product_refrigerator)

        first_move = man_order.move_raw_ids.filtered(
            lambda move: move.product_id == self.product_component1)
        self.assertEqual(first_move.product_qty, 6.0)
        first_move = man_order.move_raw_ids.filtered(
            lambda move: move.product_id == self.product_component2)
        self.assertEqual(first_move.product_qty, 2.0)

        # produce product
        mo_form = Form(man_order.with_user(self.allow_user))
        mo_form.qty_producing = 2
        man_order = mo_form.save()
        man_order.button_mark_done()

        landed_cost = Form(self.env['stock.landed.cost'].with_user(
            self.allow_user)).save()
        landed_cost.target_model = 'manufacturing'

        self.assertTrue(
            man_order.id in landed_cost.allowed_mrp_production_ids.ids)
        landed_cost.mrp_production_ids = [(6, 0, [man_order.id])]
        landed_cost.cost_lines = [(0, 0, {
            'product_id': self.landed_cost.id,
            'price_unit': 5.0,
            'split_method': 'equal'
        })]

        landed_cost.button_validate()

        self.assertEqual(landed_cost.state, 'done')
        self.assertTrue(landed_cost.account_move_id)
        # Link to one layer of product_refrigerator
        self.assertEqual(len(landed_cost.stock_valuation_layer_ids), 1)
        self.assertEqual(landed_cost.stock_valuation_layer_ids.product_id,
                         self.product_refrigerator)
        self.assertEqual(landed_cost.stock_valuation_layer_ids.value, 5.0)
Exemple #8
0
    def test_pack_in_receipt_two_step_multi_putaway(self):
        """ Checks all works right in the following specific corner case:

          * For a two-step receipt, receives two products using two putaways
          targeting different locations.
          * Puts these products in a package then valid the receipt.
          * Cancels the automatically generated internal transfer then create a new one.
          * In this internal transfer, adds the package then valid it.
        """
        grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
        grp_multi_step_rule = self.env.ref('stock.group_adv_location')
        grp_pack = self.env.ref('stock.group_tracking_lot')
        self.env.user.write({'groups_id': [(3, grp_multi_loc.id)]})
        self.env.user.write({'groups_id': [(3, grp_multi_step_rule.id)]})
        self.env.user.write({'groups_id': [(3, grp_pack.id)]})
        self.warehouse.reception_steps = 'two_steps'
        # Settings of receipt.
        self.warehouse.in_type_id.show_operations = True
        self.warehouse.in_type_id.show_entire_packs = True
        # Settings of internal transfer.
        self.warehouse.int_type_id.show_operations = True
        self.warehouse.int_type_id.show_entire_packs = True

        # Creates two new locations for putaway.
        location_form = Form(self.env['stock.location'])
        location_form.name = 'Shelf A'
        location_form.location_id = self.stock_location
        loc_shelf_A = location_form.save()
        location_form = Form(self.env['stock.location'])
        location_form.name = 'Shelf B'
        location_form.location_id = self.stock_location
        loc_shelf_B = location_form.save()

        # Creates a new putaway rule for productA and productB.
        putaway = self.env['product.putaway'].create({
            'name':
            'Stock Putaway',
            'product_location_ids': [(0, 0, {
                'product_id': self.productA.id,
                'fixed_location_id': loc_shelf_A.id,
            }),
                                     (0, 0, {
                                         'product_id': self.productB.id,
                                         'fixed_location_id': loc_shelf_B.id,
                                     })]
        })
        location_form = Form(self.stock_location)
        location_form.putaway_strategy_id = putaway
        self.stock_location = location_form.save()

        # Create a new receipt with the two products.
        receipt_form = Form(self.env['stock.picking'])
        receipt_form.picking_type_id = self.warehouse.in_type_id
        # Add 2 lines
        with receipt_form.move_ids_without_package.new() as move_line:
            move_line.product_id = self.productA
            move_line.product_uom_qty = 1
        with receipt_form.move_ids_without_package.new() as move_line:
            move_line.product_id = self.productB
            move_line.product_uom_qty = 1
        receipt = receipt_form.save()
        receipt.action_confirm()

        # Adds quantities then packs them and valids the receipt.
        receipt_form = Form(receipt)
        with receipt_form.move_line_ids_without_package.edit(0) as move_line:
            move_line.qty_done = 1
        with receipt_form.move_line_ids_without_package.edit(1) as move_line:
            move_line.qty_done = 1
        receipt = receipt_form.save()
        receipt.put_in_pack()
        receipt.button_validate()

        receipt_package = receipt.package_level_ids_details[0]
        self.assertEqual(receipt_package.location_dest_id.id,
                         receipt.location_dest_id.id)
        self.assertEqual(receipt_package.move_line_ids[0].location_dest_id.id,
                         receipt.location_dest_id.id)
        self.assertEqual(receipt_package.move_line_ids[1].location_dest_id.id,
                         receipt.location_dest_id.id)

        # Checks an internal transfer was created following the validation of the receipt.
        internal_transfer = self.env['stock.picking'].search(
            [('picking_type_id', '=', self.warehouse.int_type_id.id)],
            order='id desc',
            limit=1)
        self.assertEqual(internal_transfer.origin, receipt.name)
        self.assertEqual(len(internal_transfer.package_level_ids_details), 1)
        internal_package = internal_transfer.package_level_ids_details[0]
        self.assertEqual(internal_package.location_dest_id.id,
                         internal_transfer.location_dest_id.id)
        self.assertNotEqual(
            internal_package.location_dest_id.id,
            putaway.product_location_ids[0].fixed_location_id.id,
            "The package destination location must be the one from the picking."
        )
        self.assertNotEqual(
            internal_package.move_line_ids[0].location_dest_id.id,
            putaway.product_location_ids[0].fixed_location_id.id,
            "The move line destination location must be the one from the picking."
        )
        self.assertNotEqual(
            internal_package.move_line_ids[1].location_dest_id.id,
            putaway.product_location_ids[0].fixed_location_id.id,
            "The move line destination location must be the one from the picking."
        )

        # Cancels the internal transfer and creates a new one.
        internal_transfer.action_cancel()
        internal_form = Form(self.env['stock.picking'])
        internal_form.picking_type_id = self.warehouse.int_type_id
        internal_form.location_id = self.warehouse.wh_input_stock_loc_id
        with internal_form.package_level_ids_details.new() as pack_line:
            pack_line.package_id = receipt_package.package_id
        internal_transfer = internal_form.save()

        # Checks the package fields have been correctly set.
        internal_package = internal_transfer.package_level_ids_details[0]
        self.assertEqual(internal_package.location_dest_id.id,
                         internal_transfer.location_dest_id.id)
        internal_transfer.action_assign()
        self.assertEqual(internal_package.location_dest_id.id,
                         internal_transfer.location_dest_id.id)
        self.assertNotEqual(
            internal_package.location_dest_id.id,
            putaway.product_location_ids[0].fixed_location_id.id,
            "The package destination location must be the one from the picking."
        )
        self.assertNotEqual(
            internal_package.move_line_ids[0].location_dest_id.id,
            putaway.product_location_ids[0].fixed_location_id.id,
            "The move line destination location must be the one from the picking."
        )
        self.assertNotEqual(
            internal_package.move_line_ids[1].location_dest_id.id,
            putaway.product_location_ids[0].fixed_location_id.id,
            "The move line destination location must be the one from the picking."
        )
        internal_transfer.button_validate()
Exemple #9
0
    def test_action_assign_package_level(self):
        """calling _action_assign on move does not erase lines' "result_package_id"
        At the end of the method ``StockMove._action_assign()``, the method
        ``StockPicking._check_entire_pack()`` is called. This method compares
        the move lines with the quants of their source package, and if the entire
        package is moved at once in the same transfer, a ``stock.package_level`` is
        created. On creation of a ``stock.package_level``, the result package of
        the move lines is directly updated with the entire package.
        This is good on the first assign of the move, but when we call assign for
        the second time on a move, for instance because it was made partially available
        and we want to assign the remaining, it can override the result package we
        selected before.
        An override of ``StockPicking._check_move_lines_map_quant_package()`` ensures
        that we ignore:
        * picked lines (qty_done > 0)
        * lines with a different result package already
        """
        package = self.env["stock.quant.package"].create({"name": "Src Pack"})
        dest_package1 = self.env["stock.quant.package"].create(
            {"name": "Dest Pack1"})

        # Create new picking: 120 productA
        picking_form = Form(self.env['stock.picking'])
        picking_form.picking_type_id = self.warehouse.pick_type_id
        with picking_form.move_ids_without_package.new() as move_line:
            move_line.product_id = self.productA
            move_line.product_uom_qty = 120
        picking = picking_form.save()

        # mark as TO-DO
        picking.action_confirm()

        # Update quantity on hand: 100 units in package
        self.env['stock.quant']._update_available_quantity(self.productA,
                                                           self.stock_location,
                                                           100,
                                                           package_id=package)

        # Check Availability
        picking.action_assign()

        self.assertEqual(picking.state, "assigned")
        self.assertEqual(picking.package_level_ids.package_id, package)

        move = picking.move_lines
        line = move.move_line_ids

        # change the result package and set a qty_done
        line.qty_done = 100
        line.result_package_id = dest_package1

        # Update quantity on hand: 20 units in new_package
        new_package = self.env["stock.quant.package"].create(
            {"name": "New Pack"})
        self.env['stock.quant']._update_available_quantity(
            self.productA, self.stock_location, 20, package_id=new_package)

        # Check Availability
        picking.action_assign()

        # Check that result package is not changed on first line
        new_line = move.move_line_ids - line
        self.assertRecordValues(
            line + new_line,
            [
                {
                    "qty_done": 100,
                    "result_package_id": dest_package1.id
                },
                {
                    "qty_done": 0,
                    "result_package_id": new_package.id
                },
            ],
        )
    def test_standard_delivered_invoice_post_partial_delivery(self):
        """Standard price set to 10. Get 2 units in stock. Sale order 2@12. Deliver 1, invoice 1,
        change the standard price to 14, deliver one, change the standard price to 16, invoice 1.
        The amounts used in Stock OUT and COGS should be 10 then 14."""
        self.product.categ_id.property_cost_method = 'standard'
        self.product.invoice_policy = 'delivery'
        self.product.standard_price = 10

        # Put two items in stock.
        sale_order = self._so_and_confirm_two_units()

        # Create and confirm a sale order for 2@12
        sale_order = self._so_and_confirm_two_units()

        # Deliver one.
        sale_order.picking_ids.move_lines.quantity_done = 1
        wiz = sale_order.picking_ids.button_validate()
        wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
        wiz.process()

        # Invoice 1
        invoice = sale_order._create_invoices()
        invoice_form = Form(invoice)
        with invoice_form.invoice_line_ids.edit(0) as invoice_line:
            invoice_line.quantity = 1
        invoice_form.save()
        invoice.action_post()

        # Check the resulting accounting entries
        amls = invoice.line_ids
        self.assertEqual(len(amls), 4)
        stock_out_aml = amls.filtered(lambda aml: aml.account_id == self.company_data['default_account_stock_out'])
        self.assertEqual(stock_out_aml.debit, 0)
        self.assertEqual(stock_out_aml.credit, 10)
        cogs_aml = amls.filtered(lambda aml: aml.account_id == self.company_data['default_account_expense'])
        self.assertEqual(cogs_aml.debit, 10)
        self.assertEqual(cogs_aml.credit, 0)
        receivable_aml = amls.filtered(lambda aml: aml.account_id == self.company_data['default_account_receivable'])
        self.assertEqual(receivable_aml.debit, 12)
        self.assertEqual(receivable_aml.credit, 0)
        income_aml = amls.filtered(lambda aml: aml.account_id == self.company_data['default_account_revenue'])
        self.assertEqual(income_aml.debit, 0)
        self.assertEqual(income_aml.credit, 12)

        # change the standard price to 14
        self.product.standard_price = 14.0

        # deliver the backorder
        sale_order.picking_ids[0].move_lines.quantity_done = 1
        sale_order.picking_ids[0].button_validate()

        # change the standard price to 16
        self.product.standard_price = 16.0

        # invoice 1
        invoice2 = sale_order._create_invoices()
        invoice2.action_post()
        amls = invoice2.line_ids
        self.assertEqual(len(amls), 4)
        stock_out_aml = amls.filtered(lambda aml: aml.account_id == self.company_data['default_account_stock_out'])
        self.assertEqual(stock_out_aml.debit, 0)
        self.assertEqual(stock_out_aml.credit, 14)
        cogs_aml = amls.filtered(lambda aml: aml.account_id == self.company_data['default_account_expense'])
        self.assertEqual(cogs_aml.debit, 14)
        self.assertEqual(cogs_aml.credit, 0)
        receivable_aml = amls.filtered(lambda aml: aml.account_id == self.company_data['default_account_receivable'])
        self.assertEqual(receivable_aml.debit, 12)
        self.assertEqual(receivable_aml.credit, 0)
        income_aml = amls.filtered(lambda aml: aml.account_id == self.company_data['default_account_revenue'])
        self.assertEqual(income_aml.debit, 0)
        self.assertEqual(income_aml.credit, 12)
Exemple #11
0
    def test_reconcile_payment(self):
        tax = self.env['account.tax'].create({
            'name': 'tax abc',
            'type_tax_use': 'purchase',
            'amount_type': 'percent',
            'amount': 15,
            'price_include': False,
            'include_base_amount': False,
            'tax_exigibility': 'on_payment'
        })
        current_assets_type = self.env.ref(
            'account.data_account_type_current_assets')
        company = self.env.company.id
        tax.cash_basis_transition_account_id = self.env[
            'account.account'].create({
                'name': "test",
                'code': 999991,
                'reconcile': True,
                'user_type_id': current_assets_type.id,
                'company_id': company,
            }).id

        sheet = self.env['hr.expense.sheet'].create({
            'company_id':
            company,
            'employee_id':
            self.expense_employee.id,
            'name':
            'test sheet',
            'expense_line_ids': [
                (0, 0, {
                    'name': 'expense_1',
                    'date': '2016-01-01',
                    'product_id': self.product_a.id,
                    'unit_amount': 10.0,
                    'employee_id': self.expense_employee.id,
                    'tax_ids': tax
                }),
                (0, 0, {
                    'name': 'expense_2',
                    'date': '2016-01-01',
                    'product_id': self.product_a.id,
                    'unit_amount': 1.0,
                    'employee_id': self.expense_employee.id,
                    'tax_ids': tax
                }),
            ],
        })

        #actions
        sheet.action_submit_sheet()
        sheet.approve_expense_sheets()
        sheet.action_sheet_move_create()
        action_data = sheet.action_register_payment()
        wizard = Form(self.env['account.payment.register'].with_context(
            action_data['context'])).save()
        wizard.action_create_payments()
        self.assertEqual(
            sheet.state, 'done',
            'all account.move.line linked to expenses must be reconciled after payment'
        )
Exemple #12
0
 def setUpClass(cls):
     super().setUpClass()
     cls.env = cls.env(context=dict(
         cls.env.context, tracking_disable=True, no_reset_password=True))
     # Create new user allowed to change invoice due date
     group = cls.env.ref(
         "account_invoice_date_due.allow_to_change_due_date")
     acc_group = cls.env.ref("account.group_account_manager")
     # Loose dependency on stock to avoid perm issues.
     # We don't really care about such permissions in this context!
     # Eg:
     # odoo.exceptions.AccessError:
     # You are not allowed to access 'Stock Valuation Layer' (stock.valuation.layer) records.
     stock_group = (cls.env.ref("stock.group_stock_manager", False)
                    or cls.env["res.groups"])
     cls.user_w_access = cls.env["res.users"].create({
         "name":
         "Test User w/ access",
         "login":
         "******",
         "email":
         "*****@*****.**",
         "groups_id": [(6, 0, (group + acc_group + stock_group).ids)],
     })
     # Create new user not allowed to change invoice due date
     cls.user_wo_access = cls.env["res.users"].create({
         "name":
         "Test User wo/ access",
         "login":
         "******",
         "groups_id": [(6, 0, (acc_group + stock_group).ids)],
     })
     account100 = cls.env["account.account"].create({
         "code":
         "100",
         "name":
         "Account 100",
         "user_type_id":
         cls.env.ref("account.data_account_type_receivable").id,
         "reconcile":
         True,
     })
     account300 = cls.env["account.account"].create({
         "code":
         "300",
         "name":
         "Account 300",
         "user_type_id":
         cls.env.ref("account.data_account_type_other_income").id,
     })
     move_form = Form(cls.env["account.move"])
     move_form.date = fields.Date.today()
     with move_form.invoice_line_ids.new() as line_form:
         line_form.name = "move test"
         line_form.debit = 0.0
         line_form.credit = 1000.0
         line_form.account_id = account300
     with move_form.invoice_line_ids.new() as line_form:
         line_form.name = "move test"
         line_form.debit = 1000.0
         line_form.credit = 0.0
         line_form.account_id = account100
     cls.move = move_form.save()
Exemple #13
0
    def test_00_delivery_cost(self):
        # In order to test Carrier Cost
        # Create sales order with Normal Delivery Charges

        self.sale_normal_delivery_charges = self.SaleOrder.create({
            'partner_id': self.partner_18.id,
            'partner_invoice_id': self.partner_18.id,
            'partner_shipping_id': self.partner_18.id,
            'pricelist_id': self.pricelist.id,
            'order_line': [(0, 0, {
                'name': 'PC Assamble + 2GB RAM',
                'product_id': self.product_4.id,
                'product_uom_qty': 1,
                'product_uom': self.product_uom_unit.id,
                'price_unit': 750.00,
            })],
        })
        # I add delivery cost in Sales order

        self.a_sale = self.AccountAccount.create({
            'code': 'X2020',
            'name': 'Product Sales - (test)',
            'user_type_id': self.account_data.id,
            'tag_ids': [(6, 0, {
                self.account_tag_operating.id
            })]
        })

        self.product_consultant = self.Product.create({
            'sale_ok': True,
            'list_price': 75.0,
            'standard_price': 30.0,
            'uom_id': self.product_uom_hour.id,
            'uom_po_id': self.product_uom_hour.id,
            'name': 'Service',
            'categ_id': self.product_category.id,
            'type': 'service'
        })

        # I add delivery cost in Sales order
        delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
            'default_order_id': self.sale_normal_delivery_charges.id,
            'default_carrier_id': self.normal_delivery.id
        }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()

        # I check sales order after added delivery cost

        line = self.SaleOrderLine.search([('order_id', '=', self.sale_normal_delivery_charges.id),
            ('product_id', '=', self.normal_delivery.product_id.id)])
        self.assertEqual(len(line), 1, "Delivery cost is not Added")

        self.assertEqual(float_compare(line.price_subtotal, 10.0, precision_digits=2), 0,
            "Delivery cost is not correspond.")

        # I confirm the sales order

        self.sale_normal_delivery_charges.action_confirm()

        # Create one more sales order with Free Delivery Charges

        self.delivery_sale_order_cost = self.SaleOrder.create({
            'partner_id': self.partner_4.id,
            'partner_invoice_id': self.partner_address_13.id,
            'partner_shipping_id': self.partner_address_13.id,
            'pricelist_id': self.pricelist.id,
            'order_line': [(0, 0, {
                'name': 'Service on demand',
                'product_id': self.product_consultant.id,
                'product_uom_qty': 24,
                'product_uom': self.product_uom_hour.id,
                'price_unit': 75.00,
            }), (0, 0, {
                'name': 'On Site Assistance',
                'product_id': self.product_2.id,
                'product_uom_qty': 30,
                'product_uom': self.product_uom_hour.id,
                'price_unit': 38.25,
            })],
        })

        # I add free delivery cost in Sales order
        delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
            'default_order_id': self.delivery_sale_order_cost.id,
            'default_carrier_id': self.free_delivery.id
        }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()

        # I check sales order after adding delivery cost
        line = self.SaleOrderLine.search([('order_id', '=', self.delivery_sale_order_cost.id),
            ('product_id', '=', self.free_delivery.product_id.id)])

        self.assertEqual(len(line), 1, "Delivery cost is not Added")
        self.assertEqual(float_compare(line.price_subtotal, 0, precision_digits=2), 0,
            "Delivery cost is not correspond.")

        # I set default delivery policy

        self.default_delivery_policy = self.SaleConfigSetting.create({})

        self.default_delivery_policy.execute()
    def test_free_shipping_reward(self):
        # Test case 1: The minimum amount is not reached, the reward should
        # not be created
        self.immediate_promotion_program.active = False
        self.env['sale.coupon.program'].create({
            'name':
            'Free Shipping if at least 100 euros',
            'promo_code_usage':
            'no_code_needed',
            'reward_type':
            'free_shipping',
            'rule_minimum_amount':
            100.0,
            'rule_minimum_amount_tax_inclusion':
            'tax_included',
            'active':
            True,
        })

        order = self.env['sale.order'].create({
            'partner_id': self.steve.id,
        })

        # Price of order will be 5*1.15 = 5.75 (tax included)
        order.write({
            'order_line': [(0, False, {
                'product_id': self.product_B.id,
                'name': 'Product B',
                'product_uom': self.uom_unit.id,
                'product_uom_qty': 1.0,
            })]
        })
        order.recompute_coupon_lines()
        self.assertEqual(len(order.order_line.ids), 1)

        # I add delivery cost in Sales order
        delivery_wizard = Form(
            self.env['choose.delivery.carrier'].with_context({
                'default_order_id':
                order.id,
                'default_carrier_id':
                self.env['delivery.carrier'].search([])[1]
            }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()

        order.recompute_coupon_lines()
        self.assertEqual(len(order.order_line.ids), 2)

        # Test Case 1b: amount is not reached but is on a threshold
        # The amount of deliverable product + the one of the delivery exceeds the minimum amount
        # yet the program shouldn't be applied
        # Order price will be 5.75 + 81.74*1.15 = 99.75
        order.write({
            'order_line': [(0, False, {
                'product_id': self.product_B.id,
                'name': 'Product 1B',
                'product_uom': self.uom_unit.id,
                'product_uom_qty': 1.0,
                'price_unit': 81.74,
            })]
        })
        order.recompute_coupon_lines()
        self.assertEqual(len(order.order_line.ids), 3)

        # Test case 2: the amount is sufficient, the shipping should
        # be reimbursed
        order.write({
            'order_line': [(0, False, {
                'product_id': self.product_A.id,
                'name': 'Product 1',
                'product_uom': self.uom_unit.id,
                'product_uom_qty': 1.0,
                'price_unit': 0.30,
            })]
        })

        order.recompute_coupon_lines()
        self.assertEqual(len(order.order_line.ids), 5)

        # Test case 3: the amount is not sufficient now, the reward should be removed
        order.write({
            'order_line':
            [(2,
              order.order_line.filtered(
                  lambda line: line.product_id.id == self.product_A.id).id,
              False)]
        })
        order.recompute_coupon_lines()
        self.assertEqual(len(order.order_line.ids), 3)
    def test_vendor_bill_flow_continental_1(self):
        """In continental accounting, receive 10@10 and invoice. Then invoice 1@50 as a landed costs
        and create a linked landed costs record.
        """
        self.env.company.anglo_saxon_accounting = False

        # Create an RFQ for self.product1, 10@10
        rfq = Form(self.env['purchase.order'])
        rfq.partner_id = self.vendor1

        with rfq.order_line.new() as po_line:
            po_line.product_id = self.product1
            po_line.product_qty = 10
            po_line.price_unit = 10
            po_line.taxes_id.clear()

        rfq = rfq.save()
        rfq.button_confirm()

        # Process the receipt
        receipt = rfq.picking_ids
        wiz = receipt.button_validate()
        wiz = Form(self.env['stock.immediate.transfer'].with_context(
            wiz['context'])).save().process()
        self.assertEqual(rfq.order_line.qty_received, 10)

        input_aml = self._get_stock_input_move_lines()[-1]
        self.assertEqual(input_aml.debit, 0)
        self.assertEqual(input_aml.credit, 100)
        valuation_aml = self._get_stock_valuation_move_lines()[-1]
        self.assertEqual(valuation_aml.debit, 100)
        self.assertEqual(valuation_aml.credit, 0)

        # Create a vebdor bill for the RFQ
        action = rfq.action_create_invoice()
        vb = self.env['account.move'].browse(action['res_id'])
        vb.action_post()

        expense_aml = self._get_expense_move_lines()[-1]
        self.assertEqual(expense_aml.debit, 100)
        self.assertEqual(expense_aml.credit, 0)

        payable_aml = self._get_payable_move_lines()[-1]
        self.assertEqual(payable_aml.debit, 0)
        self.assertEqual(payable_aml.credit, 100)

        # Create a vendor bill for a landed cost product, post it and validate a landed cost
        # linked to this vendor bill. LC; 1@50
        lcvb = Form(self.env['account.move'].with_context(
            default_move_type='in_invoice'))
        lcvb.partner_id = self.vendor2
        with lcvb.invoice_line_ids.new() as inv_line:
            inv_line.product_id = self.productlc1
            inv_line.price_unit = 50
            inv_line.is_landed_costs_line = True
        with lcvb.invoice_line_ids.edit(0) as inv_line:
            inv_line.tax_ids.clear()
        lcvb = lcvb.save()
        lcvb.action_post()

        expense_aml = self._get_expense_move_lines()[-1]
        self.assertEqual(expense_aml.debit, 50)
        self.assertEqual(expense_aml.credit, 0)
        payable_aml = self._get_payable_move_lines()[-1]
        self.assertEqual(payable_aml.debit, 0)
        self.assertEqual(payable_aml.credit, 50)

        action = lcvb.button_create_landed_costs()
        lc = Form(self.env[action['res_model']].browse(action['res_id']))
        lc.picking_ids.add(receipt)
        lc = lc.save()
        lc.button_validate()

        self.assertEqual(lc.cost_lines.price_unit, 50)
        self.assertEqual(lc.cost_lines.product_id, self.productlc1)

        expense_aml = self._get_expense_move_lines()[-1]
        self.assertEqual(expense_aml.debit, 0)
        self.assertEqual(expense_aml.credit, 50)
        valuation_aml = self._get_stock_valuation_move_lines()[-1]
        self.assertEqual(valuation_aml.debit, 50)
        self.assertEqual(valuation_aml.credit, 0)

        self.assertEqual(self.product1.quantity_svl, 10)
        self.assertEqual(self.product1.value_svl, 150)
Exemple #16
0
    def test_mrp_subcontracting_dropshipping_1(self):
        """ Mark the subcontracted product with the route dropship and add the
        subcontractor as seller. The component has the routes 'MTO', 'Replenish
        on order' and 'Buy'. Also another partner is set as vendor on the comp.
        Create a SO and check that:
        - Delivery between subcontractor and customer for subcontracted product.
        - Delivery for the component to the subcontractor for the specified wh.
        - Po created for the component.
        """
        mto_route = self.env['stock.location.route'].search([
            ('name', '=', 'Replenish on Order (MTO)')
        ])
        resupply_route = self.env['stock.location.route'].search([
            ('name', '=', 'Resupply Subcontractor on Order')
        ])
        buy_route = self.env['stock.location.route'].search([('name', '=',
                                                              'Buy')])
        dropship_route = self.env['stock.location.route'].search([
            ('name', '=', 'Dropship')
        ])
        self.comp2.write({
            'route_ids': [(4, buy_route.id), (4, mto_route.id),
                          (4, resupply_route.id)]
        })
        self.finished.write({'route_ids': [(4, dropship_route.id)]})

        warehouse = self.env['stock.warehouse'].create({
            'name': 'Warehouse For subcontract',
            'code': 'WFS'
        })

        self.env['product.supplierinfo'].create({
            'product_tmpl_id':
            self.finished.product_tmpl_id.id,
            'name':
            self.subcontractor_partner1.id
        })

        partner = self.env['res.partner'].create({'name': 'Toto'})
        self.env['product.supplierinfo'].create({
            'product_tmpl_id':
            self.comp2.product_tmpl_id.id,
            'name':
            partner.id
        })

        # Create a receipt picking from the subcontractor
        so_form = Form(self.env['sale.order'])
        so_form.partner_id = partner
        so_form.warehouse_id = warehouse
        with so_form.order_line.new() as line:
            line.product_id = self.finished
            line.product_uom_qty = 1
        so = so_form.save()
        so.action_confirm()

        # Pickings should directly be created
        po = self.env['purchase.order'].search([('origin', 'ilike', so.name)])
        self.assertTrue(po)

        po.button_approve()

        picking_finished = po.picking_ids
        self.assertEqual(len(picking_finished), 1.0)
        self.assertEqual(picking_finished.location_dest_id,
                         partner.property_stock_customer)
        self.assertEqual(picking_finished.location_id,
                         self.subcontractor_partner1.property_stock_supplier)
        self.assertEqual(picking_finished.state, 'assigned')

        picking_delivery = self.env['stock.move'].search([
            ('product_id', '=', self.comp2.id),
            ('location_id', '=', warehouse.lot_stock_id.id),
            ('location_dest_id', '=',
             self.subcontractor_partner1.property_stock_subcontractor.id),
        ]).picking_id
        self.assertTrue(picking_delivery)
        self.assertEqual(picking_delivery.state, 'waiting')

        po = self.env['purchase.order.line'].search([
            ('product_id', '=', self.comp2.id),
            ('partner_id', '=', partner.id),
        ]).order_id
        self.assertTrue(po)
Exemple #17
0
    def test_00_shipping_info(self):
        # Create sale order with Normal Delivery Charges
        self.percent_tax = self.tax_model.create({
            "name": "Percent tax",
            "amount_type": "percent",
            "amount": 10,
            "sequence": 3,
        })
        self.normal_delivery.product_id.taxes_id = self.percent_tax
        self.sale = self.SaleOrder.create({
            "partner_id":
            self.partner_18.id,
            "partner_invoice_id":
            self.partner_18.id,
            "partner_shipping_id":
            self.partner_18.id,
            "pricelist_id":
            self.pricelist.id,
            "order_line": [(
                0,
                0,
                {
                    "name": "PC Assamble + 2GB RAM",
                    "product_id": self.product_4.id,
                    "product_uom_qty": 1,
                    "product_uom": self.product_uom_unit.id,
                    "price_unit": 750.00,
                    "tax_id": [(4, self.percent_tax.id, 0)],
                },
            )],
            "carrier_id":
            self.normal_delivery.id,
        })

        # set delivery cost in Sales order
        delivery_wizard = Form(
            self.env["choose.delivery.carrier"].with_context({
                "default_order_id":
                self.sale.id,
                "default_carrier_id":
                self.normal_delivery.id,
            }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()

        # check sale order computed field after added delivery cost
        line = self.SaleOrderLine.search([
            ("order_id", "=", self.sale.id),
            ("product_id", "=", self.sale.carrier_id.product_id.id),
        ])
        self.assertEqual(len(line), 1, "Delivery cost is not Added")
        self.assertEqual(
            float_compare(line.price_subtotal, 10, precision_digits=2),
            0,
            "Sale line delivery price subtotal is not correct",
        )
        self.assertEqual(
            float_compare(line.price_total, 11, precision_digits=2),
            0,
            "Sale line delivery price total is not correct",
        )
        self.assertEqual(
            float_compare(line.price_tax, 1, precision_digits=2),
            0,
            "Sale line delivery price tax is not correct",
        )
        self.assertEqual(
            float_compare(self.sale.shipping_amount_tax, 1,
                          precision_digits=2),
            0,
            "Shipping amount tax is not correct",
        )
        self.assertEqual(
            float_compare(self.sale.shipping_amount_untaxed,
                          10,
                          precision_digits=2),
            0,
            "Shipping amount untaxed is not correct",
        )
        self.assertEqual(
            float_compare(self.sale.shipping_amount_total,
                          11,
                          precision_digits=2),
            0,
            "Shipping amount total is not correct",
        )
        self.assertEqual(
            float_compare(self.sale.item_amount_tax, 75, precision_digits=2),
            0,
            "Item amount tax is not correct",
        )
        self.assertEqual(
            float_compare(self.sale.item_amount_untaxed,
                          750,
                          precision_digits=2),
            0,
            "Item amount untaxed is not correct",
        )
        self.assertEqual(
            float_compare(self.sale.item_amount_total,
                          825.0,
                          precision_digits=2),
            0,
            "Item amount total is not correct",
        )
Exemple #18
0
    def test_mrp_subcontracting_purchase_2(self):
        """Let's consider a subcontracted BOM with 1 component. Tick "Resupply Subcontractor on Order" on the component and set a supplier on it.
        Purchase 1 BOM to the subcontractor. Confirm the purchase and change the purchased quantity to 2.
        Check that 2 components are delivered to the subcontractor
        """
        # Tick "resupply subconractor on order on component"
        self.bom.bom_line_ids = [(5, 0, 0)]
        self.bom.bom_line_ids = [(0, 0, {
            'product_id': self.comp1.id,
            'product_qty': 1
        })]
        resupply_sub_on_order_route = self.env['stock.location.route'].search([
            ('name', '=', 'Resupply Subcontractor on Order')
        ])
        (self.comp1).write(
            {'route_ids': [(4, resupply_sub_on_order_route.id, None)]})
        # Create a supplier and set it to component
        vendor = self.env['res.partner'].create({
            'name':
            'AAA',
            'email':
            '*****@*****.**'
        })
        supplier_info1 = self.env['product.supplierinfo'].create({
            'name':
            vendor.id,
            'price':
            50,
        })
        self.comp1.write({
            'seller_ids': [(0, 0, {
                'name': vendor.id,
                'product_code': 'COMP1'
            })]
        })
        # Purchase 1 BOM to the subcontractor
        po = Form(self.env['purchase.order'])
        po.partner_id = self.subcontractor_partner1
        with po.order_line.new() as po_line:
            po_line.product_id = self.finished
            po_line.product_qty = 1
            po_line.price_unit = 100
        po = po.save()
        # Confirm the purchase
        po.button_confirm()
        # Check one delivery order with the component has been created for the subcontractor
        mo = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)])
        self.assertEqual(mo.state, 'confirmed')
        # Check that 1 delivery with 1 component for the subcontractor has been created
        picking_delivery = mo.picking_ids
        wh = picking_delivery.picking_type_id.warehouse_id
        origin = picking_delivery.origin
        self.assertEqual(len(picking_delivery), 1)
        self.assertEqual(len(picking_delivery.move_ids_without_package), 1)
        self.assertEqual(picking_delivery.picking_type_id, wh.out_type_id)
        self.assertEqual(picking_delivery.partner_id,
                         self.subcontractor_partner1)

        # Change the purchased quantity to 2
        po.order_line.write({'product_qty': 2})
        # Check that two deliveries with 1 component for the subcontractor have been created
        picking_deliveries = self.env['stock.picking'].search([('origin', '=',
                                                                origin)])
        self.assertEqual(len(picking_deliveries), 2)
        self.assertEqual(picking_deliveries[0].picking_type_id, wh.out_type_id)
        self.assertEqual(picking_deliveries[0].partner_id,
                         self.subcontractor_partner1)
        self.assertTrue(picking_deliveries[0].state != 'cancel')
        move1 = picking_deliveries[0].move_ids_without_package
        self.assertEqual(picking_deliveries[1].picking_type_id, wh.out_type_id)
        self.assertEqual(picking_deliveries[1].partner_id,
                         self.subcontractor_partner1)
        self.assertTrue(picking_deliveries[1].state != 'cancel')
        move2 = picking_deliveries[1].move_ids_without_package
        self.assertEqual(move1.product_id, self.comp1)
        self.assertEqual(move1.product_uom_qty, 1)
        self.assertEqual(move2.product_id, self.comp1)
        self.assertEqual(move2.product_uom_qty, 1)
Exemple #19
0
    def test_toggle_active_warehouse_2(self):
        wh = Form(self.env['stock.warehouse'])
        wh.name = "The attic of Willy"
        wh.code = "WIL"
        wh.reception_steps = "two_steps"
        wh.delivery_steps = "pick_pack_ship"
        warehouse = wh.save()

        warehouse.resupply_wh_ids = [(6, 0, [self.warehouse_1.id])]

        custom_location = Form(self.env['stock.location'])
        custom_location.name = "A Trunk"
        custom_location.location_id = warehouse.lot_stock_id
        custom_location = custom_location.save()

        # Add a warehouse on the route.
        warehouse.reception_route_id.write(
            {'warehouse_ids': [(4, self.warehouse_1.id)]})

        route = Form(self.env['stock.location.route'])
        route.name = "Stair"
        route = route.save()

        route.warehouse_ids = [(6, 0, [warehouse.id, self.warehouse_1.id])]

        # Pre archive a location and a route
        warehouse.delivery_route_id.toggle_active()
        warehouse.wh_pack_stock_loc_id.toggle_active()

        # Archive warehouse
        warehouse.toggle_active()
        # Global rule
        self.assertFalse(warehouse.mto_pull_id.active)

        # Route
        self.assertTrue(warehouse.reception_route_id.active)
        self.assertFalse(warehouse.delivery_route_id.active)
        self.assertTrue(route.active)

        # Location
        self.assertFalse(warehouse.lot_stock_id.active)
        self.assertFalse(warehouse.wh_input_stock_loc_id.active)
        self.assertFalse(warehouse.wh_qc_stock_loc_id.active)
        self.assertFalse(warehouse.wh_output_stock_loc_id.active)
        self.assertFalse(warehouse.wh_pack_stock_loc_id.active)
        self.assertFalse(custom_location.active)

        # Picking Type
        self.assertFalse(warehouse.in_type_id.active)
        self.assertFalse(warehouse.out_type_id.active)
        self.assertFalse(warehouse.int_type_id.active)
        self.assertFalse(warehouse.pick_type_id.active)
        self.assertFalse(warehouse.pack_type_id.active)

        # Active warehouse
        warehouse.toggle_active()
        # Global rule
        self.assertTrue(warehouse.mto_pull_id.active)

        # Route
        self.assertTrue(warehouse.reception_route_id.active)
        self.assertTrue(warehouse.delivery_route_id.active)

        # Location
        self.assertTrue(warehouse.lot_stock_id.active)
        self.assertTrue(warehouse.wh_input_stock_loc_id.active)
        self.assertFalse(warehouse.wh_qc_stock_loc_id.active)
        self.assertTrue(warehouse.wh_output_stock_loc_id.active)
        self.assertTrue(warehouse.wh_pack_stock_loc_id.active)
        self.assertTrue(custom_location.active)

        # Picking Type
        self.assertTrue(warehouse.in_type_id.active)
        self.assertTrue(warehouse.out_type_id.active)
        self.assertTrue(warehouse.int_type_id.active)
        self.assertTrue(warehouse.pick_type_id.active)
        self.assertTrue(warehouse.pack_type_id.active)
Exemple #20
0
    def test_unbuild_standart(self):
        """ This test creates a MO and then creates 3 unbuild
        orders for the final product. None of the products for this
        test are tracked. It checks the stock state after each order
        and ensure it is correct.
        """
        mo, bom, p_final, p1, p2 = self.generate_mo()
        self.assertEqual(len(mo), 1, 'MO should have been created')

        self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100)
        self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5)
        mo.action_assign()

        produce_form = Form(self.env['mrp.product.produce'].with_context({
            'active_id': mo.id,
            'active_ids': [mo.id],
        }))
        produce_form.qty_producing = 5.0
        produce_wizard = produce_form.save()
        produce_wizard.do_produce()

        mo.button_mark_done()
        self.assertEqual(mo.state, 'done', "Production order should be in done state.")

        # Check quantity in stock before unbuild.
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 5, 'You should have the 5 final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 80, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 0, 'You should have consumed all the 5 product in stock')

        # ---------------------------------------------------
        #       unbuild
        # ---------------------------------------------------

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_qty = 3
        x.product_uom_id = self.uom_unit
        x.save().action_unbuild()


        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 2, 'You should have consumed 3 final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 92, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 3, 'You should have consumed all the 5 product in stock')

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_qty = 2
        x.product_uom_id = self.uom_unit
        x.save().action_unbuild()

        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 0, 'You should have 0 finalproduct in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 100, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 5, 'You should have consumed all the 5 product in stock')

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_qty = 5
        x.product_uom_id = self.uom_unit
        x.save().action_unbuild()

        # Check quantity in stock after last unbuild.
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, allow_negative=True), -5, 'You should have negative quantity for final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 120, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 10, 'You should have consumed all the 5 product in stock')
Exemple #21
0
    def test_invoice(self):
        """ Test create and invoice from the SO, and check qty invoice/to invoice, and the related amounts """
        # lines are in draft
        for line in self.sale_order.order_line:
            self.assertTrue(
                float_is_zero(line.untaxed_amount_to_invoice,
                              precision_digits=2),
                "The amount to invoice should be zero, as the line is in draf state"
            )
            self.assertTrue(
                float_is_zero(line.untaxed_amount_invoiced,
                              precision_digits=2),
                "The invoiced amount should be zero, as the line is in draft state"
            )

        # Confirm the SO
        self.sale_order.action_confirm()

        # Check ordered quantity, quantity to invoice and invoiced quantity of SO lines
        for line in self.sale_order.order_line:
            if line.product_id.invoice_policy == 'delivery':
                self.assertEqual(
                    line.qty_to_invoice, 0.0,
                    'Quantity to invoice should be same as ordered quantity')
                self.assertEqual(
                    line.qty_invoiced, 0.0,
                    'Invoiced quantity should be zero as no any invoice created for SO'
                )
                self.assertEqual(
                    line.untaxed_amount_to_invoice, 0.0,
                    "The amount to invoice should be zero, as the line based on delivered quantity"
                )
                self.assertEqual(
                    line.untaxed_amount_invoiced, 0.0,
                    "The invoiced amount should be zero, as the line based on delivered quantity"
                )
            else:
                self.assertEqual(
                    line.qty_to_invoice, line.product_uom_qty,
                    'Quantity to invoice should be same as ordered quantity')
                self.assertEqual(
                    line.qty_invoiced, 0.0,
                    'Invoiced quantity should be zero as no any invoice created for SO'
                )
                self.assertEqual(
                    line.untaxed_amount_to_invoice,
                    line.product_uom_qty * line.price_unit,
                    "The amount to invoice should the total of the line, as the line is confirmed"
                )
                self.assertEqual(
                    line.untaxed_amount_invoiced, 0.0,
                    "The invoiced amount should be zero, as the line is confirmed"
                )

        # Let's do an invoice with invoiceable lines
        payment = self.env['sale.advance.payment.inv'].with_context(
            self.context).create({'advance_payment_method': 'delivered'})
        payment.create_invoices()

        invoice = self.sale_order.invoice_ids[0]

        # Update quantity of an invoice lines
        move_form = Form(invoice)
        with move_form.invoice_line_ids.edit(0) as line_form:
            line_form.quantity = 3.0
        with move_form.invoice_line_ids.edit(1) as line_form:
            line_form.quantity = 2.0
        invoice = move_form.save()

        # amount to invoice / invoiced should not have changed (amounts take only confirmed invoice into account)
        for line in self.sale_order.order_line:
            if line.product_id.invoice_policy == 'delivery':
                self.assertEqual(line.qty_to_invoice, 0.0,
                                 "Quantity to invoice should be zero")
                self.assertEqual(
                    line.qty_invoiced, 0.0,
                    "Invoiced quantity should be zero as delivered lines are not delivered yet"
                )
                self.assertEqual(
                    line.untaxed_amount_to_invoice, 0.0,
                    "The amount to invoice should be zero, as the line based on delivered quantity (no confirmed invoice)"
                )
                self.assertEqual(
                    line.untaxed_amount_invoiced, 0.0,
                    "The invoiced amount should be zero, as no invoice are validated for now"
                )
            else:
                if line == self.sol_prod_order:
                    self.assertEqual(
                        self.sol_prod_order.qty_to_invoice, 2.0,
                        "Changing the quantity on draft invoice update the qty to invoice on SO lines"
                    )
                    self.assertEqual(
                        self.sol_prod_order.qty_invoiced, 3.0,
                        "Changing the quantity on draft invoice update the invoiced qty on SO lines"
                    )
                else:
                    self.assertEqual(
                        self.sol_serv_order.qty_to_invoice, 1.0,
                        "Changing the quantity on draft invoice update the qty to invoice on SO lines"
                    )
                    self.assertEqual(
                        self.sol_serv_order.qty_invoiced, 2.0,
                        "Changing the quantity on draft invoice update the invoiced qty on SO lines"
                    )
                self.assertEqual(
                    line.untaxed_amount_to_invoice,
                    line.product_uom_qty * line.price_unit,
                    "The amount to invoice should the total of the line, as the line is confirmed (no confirmed invoice)"
                )
                self.assertEqual(
                    line.untaxed_amount_invoiced, 0.0,
                    "The invoiced amount should be zero, as no invoice are validated for now"
                )

        invoice.action_post()

        # Check quantity to invoice on SO lines
        for line in self.sale_order.order_line:
            if line.product_id.invoice_policy == 'delivery':
                self.assertEqual(
                    line.qty_to_invoice, 0.0,
                    "Quantity to invoice should be same as ordered quantity")
                self.assertEqual(
                    line.qty_invoiced, 0.0,
                    "Invoiced quantity should be zero as no any invoice created for SO"
                )
                self.assertEqual(
                    line.untaxed_amount_to_invoice, 0.0,
                    "The amount to invoice should be zero, as the line based on delivered quantity"
                )
                self.assertEqual(
                    line.untaxed_amount_invoiced, 0.0,
                    "The invoiced amount should be zero, as the line based on delivered quantity"
                )
            else:
                if line == self.sol_prod_order:
                    self.assertEqual(
                        line.qty_to_invoice, 2.0,
                        "The ordered sale line are totally invoiced (qty to invoice is zero)"
                    )
                    self.assertEqual(
                        line.qty_invoiced, 3.0,
                        "The ordered (prod) sale line are totally invoiced (qty invoiced come from the invoice lines)"
                    )
                else:
                    self.assertEqual(
                        line.qty_to_invoice, 1.0,
                        "The ordered sale line are totally invoiced (qty to invoice is zero)"
                    )
                    self.assertEqual(
                        line.qty_invoiced, 2.0,
                        "The ordered (serv) sale line are totally invoiced (qty invoiced = the invoice lines)"
                    )
                self.assertEqual(
                    line.untaxed_amount_to_invoice,
                    line.price_unit * line.qty_to_invoice,
                    "Amount to invoice is now set as qty to invoice * unit price since no price change on invoice, for ordered products"
                )
                self.assertEqual(
                    line.untaxed_amount_invoiced,
                    line.price_unit * line.qty_invoiced,
                    "Amount invoiced is now set as qty invoiced * unit price since no price change on invoice, for ordered products"
                )
Exemple #22
0
    def test_unbuild_with_comnsumed_lot(self):
        """ This test creates a MO and then creates 3 unbuild
        orders for the final product. Only once of the two consumed
        product is tracked by lot. It checks the stock state after each
        order and ensure it is correct.
        """
        mo, bom, p_final, p1, p2 = self.generate_mo(tracking_base_1='lot')
        self.assertEqual(len(mo), 1, 'MO should have been created')

        lot = self.env['stock.production.lot'].create({
            'name': 'lot1',
            'product_id': p1.id,
            'company_id': self.env.company.id,
        })

        self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100, lot_id=lot)
        self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5)
        mo.action_assign()
        for ml in mo.move_raw_ids.mapped('move_line_ids'):
            if ml.product_id.tracking != 'none':
                self.assertEqual(ml.lot_id, lot, 'Wrong reserved lot.')

        produce_form = Form(self.env['mrp.product.produce'].with_context({
            'active_id': mo.id,
            'active_ids': [mo.id],
        }))
        produce_form.qty_producing = 5.0
        produce_wizard = produce_form.save()

        produce_wizard.do_produce()

        mo.button_mark_done()
        self.assertEqual(mo.state, 'done', "Production order should be in done state.")
        # Check quantity in stock before unbuild.
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 5, 'You should have the 5 final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location, lot_id=lot), 80, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 0, 'You should have consumed all the 5 product in stock')

        # ---------------------------------------------------
        #       unbuild
        # ---------------------------------------------------

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_qty = 3
        x.product_uom_id = self.uom_unit
        unbuild_order = x.save()

        # This should fail since we do not provide the MO that we wanted to unbuild. (without MO we do not know which consumed lot we have to restore)
        with self.assertRaises(UserError):
            unbuild_order.action_unbuild()

        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 5, 'You should have consumed 3 final product in stock')

        unbuild_order.mo_id = mo.id
        unbuild_order.action_unbuild()

        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 2, 'You should have consumed 3 final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location, lot_id=lot), 92, 'You should have 92 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 3, 'You should have consumed all the 5 product in stock')

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_uom_id = self.uom_unit
        x.mo_id = mo
        x.product_qty = 2
        x.save().action_unbuild()

        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), 0, 'You should have 0 finalproduct in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location, lot_id=lot), 100, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 5, 'You should have consumed all the 5 product in stock')

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_uom_id = self.uom_unit
        x.mo_id = mo
        x.product_qty = 5
        x.save().action_unbuild()

        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, allow_negative=True), -5, 'You should have negative quantity for final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location, lot_id=lot), 120, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 10, 'You should have consumed all the 5 product in stock')
Exemple #23
0
    def test_12_multi_level_variants2(self):
        """Test skip bom line with same attribute values in bom lines."""

        Product = self.env['product.product']
        ProductAttribute = self.env['product.attribute']
        ProductAttributeValue = self.env['product.attribute.value']

        # Product Attribute
        att_color = ProductAttribute.create({'name': 'Color', 'sequence': 1})
        att_size = ProductAttribute.create({'name': 'size', 'sequence': 2})

        # Product Attribute color Value
        att_color_red = ProductAttributeValue.create({'name': 'red', 'attribute_id': att_color.id, 'sequence': 1})
        att_color_blue = ProductAttributeValue.create({'name': 'blue', 'attribute_id': att_color.id, 'sequence': 2})
        # Product Attribute size Value
        att_size_big = ProductAttributeValue.create({'name': 'big', 'attribute_id': att_size.id, 'sequence': 1})
        att_size_medium = ProductAttributeValue.create({'name': 'medium', 'attribute_id': att_size.id, 'sequence': 2})

        # Create Template Product
        product_template = self.env['product.template'].create({
            'name': 'Sofa',
            'attribute_line_ids': [
                (0, 0, {
                    'attribute_id': att_color.id,
                    'value_ids': [(6, 0, [att_color_red.id, att_color_blue.id])]
                }),
                (0, 0, {
                    'attribute_id': att_size.id,
                    'value_ids': [(6, 0, [att_size_big.id, att_size_medium.id])]
                })
            ]
        })

        sofa_red = product_template.attribute_line_ids[0].product_template_value_ids[0]
        sofa_blue = product_template.attribute_line_ids[0].product_template_value_ids[1]

        sofa_big = product_template.attribute_line_ids[1].product_template_value_ids[0]
        sofa_medium = product_template.attribute_line_ids[1].product_template_value_ids[1]

        # Create components Of BOM
        product_A = Product.create({
            'name': 'Wood'})
        product_B = Product.create({
            'name': 'Clothes'})

        # Create BOM
        self.env['mrp.bom'].create({
            'product_tmpl_id': product_template.id,
            'product_qty': 1.0,
            'type': 'normal',
            'bom_line_ids': [
                (0, 0, {
                    'product_id': product_A.id,
                    'product_qty': 1,
                    'bom_product_template_attribute_value_ids': [(4, sofa_red.id), (4, sofa_blue.id), (4, sofa_big.id)],
                }),
                (0, 0, {
                    'product_id': product_B.id,
                    'product_qty': 1,
                    'bom_product_template_attribute_value_ids': [(4, sofa_red.id), (4, sofa_blue.id)]
                })
            ]
        })

        dict_consumed_products = {
            sofa_red + sofa_big: product_A + product_B,
            sofa_red + sofa_medium: product_B,
            sofa_blue + sofa_big: product_A + product_B,
            sofa_blue + sofa_medium: product_B,
        }

        # Create production order for all variants.
        for combination, consumed_products in dict_consumed_products.items():
            product = product_template.product_variant_ids.filtered(lambda p: p.product_template_attribute_value_ids == combination)
            mrp_order_form = Form(self.env['mrp.production'])
            mrp_order_form.product_id = product
            mrp_order = mrp_order_form.save()

            # Check consumed materials in production order.
            self.assertEqual(mrp_order.move_raw_ids.product_id, consumed_products)
Exemple #24
0
    def test_unbuild_with_routes(self):
        """ This test creates a MO of a stockable product (Table). A new route for rule QC/Unbuild -> Stock
        is created with Warehouse -> True.
        The unbuild order should revert the consumed components into QC/Unbuild location for quality check
        and then a picking should be generated for transferring components from QC/Unbuild location to stock.
        """
        StockQuant = self.env['stock.quant']
        ProductObj = self.env['product.product']
        # Create new QC/Unbuild location
        warehouse = self.env.ref('stock.warehouse0')
        unbuild_location = self.env['stock.location'].create({
            'name': 'QC/Unbuild',
            'usage': 'internal',
            'location_id': warehouse.view_location_id.id
        })

        # Create a product route containing a stock rule that will move product from QC/Unbuild location to stock
        product_route = self.env['stock.location.route'].create({
            'name': 'QC/Unbuild -> Stock',
            'warehouse_selectable': True,
            'warehouse_ids': [(4, warehouse.id)],
            'rule_ids': [(0, 0, {
                'name': 'Send Matrial QC/Unbuild -> Stock',
                'action': 'push',
                'picking_type_id': self.ref('stock.picking_type_internal'),
                'location_src_id': unbuild_location.id,
                'location_id': self.stock_location.id,
            })],
        })

        # Create a stockable product and its components
        finshed_product = ProductObj.create({
            'name': 'Table',
            'type': 'product',
        })
        component1 = ProductObj.create({
            'name': 'Table head',
            'type': 'product',
        })
        component2 = ProductObj.create({
            'name': 'Table stand',
            'type': 'product',
        })

        # Create bom and add components
        bom = self.env['mrp.bom'].create({
            'product_id': finshed_product.id,
            'product_tmpl_id': finshed_product.product_tmpl_id.id,
            'product_uom_id': self.uom_unit.id,
            'product_qty': 1.0,
            'type': 'normal',
            'bom_line_ids': [
                (0, 0, {'product_id': component1.id, 'product_qty': 1}),
                (0, 0, {'product_id': component2.id, 'product_qty': 1})
            ]})

        # Set on hand quantity
        StockQuant._update_available_quantity(component1, self.stock_location, 1)
        StockQuant._update_available_quantity(component2, self.stock_location, 1)

        # Create mo
        mo_form = Form(self.env['mrp.production'])
        mo_form.product_id = finshed_product
        mo_form.bom_id = bom
        mo_form.product_uom_id = finshed_product.uom_id
        mo_form.product_qty = 1.0
        mo = mo_form.save()
        self.assertEqual(len(mo), 1, 'MO should have been created')
        mo.action_confirm()
        mo.action_assign()

        # Produce the final product
        produce_form = Form(self.env['mrp.product.produce'].with_context({
            'active_id': mo.id,
            'active_ids': [mo.id],
        }))
        produce_form.qty_producing = 1.0
        produce_wizard = produce_form.save()
        produce_wizard.do_produce()

        mo.button_mark_done()
        self.assertEqual(mo.state, 'done', "Production order should be in done state.")

        # Check quantity in stock before unbuild
        self.assertEqual(StockQuant._get_available_quantity(finshed_product, self.stock_location), 1, 'Table should be available in stock')
        self.assertEqual(StockQuant._get_available_quantity(component1, self.stock_location), 0, 'Table head should not be available in stock')
        self.assertEqual(StockQuant._get_available_quantity(component2, self.stock_location), 0, 'Table stand should not be available in stock')

        # ---------------------------------------------------
        #       Unbuild
        # ---------------------------------------------------

        # Create an unbuild order of the finished product and set the destination loacation = QC/Unbuild
        x = Form(self.env['mrp.unbuild'])
        x.product_id = finshed_product
        x.bom_id = bom
        x.product_uom_id = self.uom_unit
        x.mo_id = mo
        x.product_qty = 1
        x.location_id = self.stock_location
        x.location_dest_id = unbuild_location
        x.save().action_unbuild()

        # Check the available quantity of components and final product in stock
        self.assertEqual(StockQuant._get_available_quantity(finshed_product, self.stock_location), 0, 'Table should not be available in stock as it is unbuild')
        self.assertEqual(StockQuant._get_available_quantity(component1, self.stock_location), 0, 'Table head should not be available in stock as it is in QC/Unbuild location')
        self.assertEqual(StockQuant._get_available_quantity(component2, self.stock_location), 0, 'Table stand should not be available in stock as it is in QC/Unbuild location')

        # Find new generated picking
        picking = self.env['stock.picking'].search([('product_id', 'in', [component1.id, component2.id])])
        self.assertEqual(picking.location_id.id, unbuild_location.id, 'Wrong source location in picking')
        self.assertEqual(picking.location_dest_id.id, self.stock_location.id, 'Wrong destination location in picking')

        # Transfer it
        for ml in picking.move_ids_without_package:
            ml.quantity_done = 1
        picking.action_done()

        # Check the available quantity of components and final product in stock
        self.assertEqual(StockQuant._get_available_quantity(finshed_product, self.stock_location), 0, 'Table should not be available in stock')
        self.assertEqual(StockQuant._get_available_quantity(component1, self.stock_location), 1, 'Table head should be available in stock as the picking is transferred')
        self.assertEqual(StockQuant._get_available_quantity(component2, self.stock_location), 1, 'Table stand should be available in stock as the picking is transferred')
Exemple #25
0
    def test_21_bom_report_variant(self):
        """ Test a sub BoM process with multiple variants.
        BOM 1:
        product template = car
        quantity = 5 units
        - red paint 50l -> red car (product.product)
        - blue paint 50l -> blue car
        - red dashboard with gps -> red car with GPS
        - red dashboard w/h gps -> red w/h GPS
        - blue dashboard with gps -> blue car with GPS
        - blue dashboard w/h gps -> blue w/h GPS

        BOM 2:
        product_tmpl = dashboard
        quantity = 2
        - red paint 1l -> red dashboard (product.product)
        - blue paint 1l -> blue dashboard
        - gps -> dashboard with gps

        Check the Price for a Blue Car with GPS -> 910$:
        10l of blue paint -> 200$
        1 blue dashboard GPS -> 710$:
            - 0.5l of blue paint -> 10$
            - GPS -> 700$

        Check the price for a red car -> 10.5l of red paint -> 210$
        """
        # Create a product template car with attributes gps(yes, no), color(red, blue)
        self.car = self.env['product.template'].create({
            'name': 'Car',
        })
        self.gps_attribute = self.env['product.attribute'].create({'name': 'GPS', 'sequence': 1})
        self.gps_yes = self.env['product.attribute.value'].create({
            'name': 'Yes',
            'attribute_id': self.gps_attribute.id,
            'sequence': 1,
        })
        self.gps_no = self.env['product.attribute.value'].create({
            'name': 'No',
            'attribute_id': self.gps_attribute.id,
            'sequence': 2,
        })

        self.car_gps_attribute_line = self.env['product.template.attribute.line'].create({
            'product_tmpl_id': self.car.id,
            'attribute_id': self.gps_attribute.id,
            'value_ids': [(6, 0, [self.gps_yes.id, self.gps_no.id])],
        })
        self.car_gps_yes = self.car_gps_attribute_line.product_template_value_ids[0]
        self.car_gps_no = self.car_gps_attribute_line.product_template_value_ids[1]

        self.color_attribute = self.env['product.attribute'].create({'name': 'Color', 'sequence': 1})
        self.color_red = self.env['product.attribute.value'].create({
            'name': 'Red',
            'attribute_id': self.color_attribute.id,
            'sequence': 1,
        })
        self.color_blue = self.env['product.attribute.value'].create({
            'name': 'Blue',
            'attribute_id': self.color_attribute.id,
            'sequence': 2,
        })

        self.car_color_attribute_line = self.env['product.template.attribute.line'].create({
            'product_tmpl_id': self.car.id,
            'attribute_id': self.color_attribute.id,
            'value_ids': [(6, 0, [self.color_red.id, self.color_blue.id])],
        })
        self.car_color_red = self.car_color_attribute_line.product_template_value_ids[0]
        self.car_color_blue = self.car_color_attribute_line.product_template_value_ids[1]

        # Blue and red paint
        uom_litre = self.env.ref('uom.product_uom_litre')
        self.paint = self.env['product.template'].create({
            'name': 'Paint',
            'uom_id': uom_litre.id,
            'uom_po_id': uom_litre.id
        })
        self.paint_color_attribute_line = self.env['product.template.attribute.line'].create({
            'product_tmpl_id': self.paint.id,
            'attribute_id': self.color_attribute.id,
            'value_ids': [(6, 0, [self.color_red.id, self.color_blue.id])],
        })
        self.paint_color_red = self.paint_color_attribute_line.product_template_value_ids[0]
        self.paint_color_blue = self.paint_color_attribute_line.product_template_value_ids[1]

        self.paint.product_variant_ids.write({'standard_price': 20})

        self.dashboard = self.env['product.template'].create({
            'name': 'Dashboard',
            'standard_price': 1000,
        })

        self.dashboard_gps_attribute_line = self.env['product.template.attribute.line'].create({
            'product_tmpl_id': self.dashboard.id,
            'attribute_id': self.gps_attribute.id,
            'value_ids': [(6, 0, [self.gps_yes.id, self.gps_no.id])],
        })
        self.dashboard_gps_yes = self.dashboard_gps_attribute_line.product_template_value_ids[0]
        self.dashboard_gps_no = self.dashboard_gps_attribute_line.product_template_value_ids[1]

        self.dashboard_color_attribute_line = self.env['product.template.attribute.line'].create({
            'product_tmpl_id': self.dashboard.id,
            'attribute_id': self.color_attribute.id,
            'value_ids': [(6, 0, [self.color_red.id, self.color_blue.id])],
        })
        self.dashboard_color_red = self.dashboard_color_attribute_line.product_template_value_ids[0]
        self.dashboard_color_blue = self.dashboard_color_attribute_line.product_template_value_ids[1]

        self.gps = self.env['product.product'].create({
            'name': 'GPS',
            'standard_price': 700,
        })

        bom_form_car = Form(self.env['mrp.bom'])
        bom_form_car.product_tmpl_id = self.car
        bom_form_car.product_qty = 5
        with bom_form_car.bom_line_ids.new() as line:
            line.product_id = self.paint._get_variant_for_combination(self.paint_color_red)
            line.product_uom_id = uom_litre
            line.product_qty = 50
            line.bom_product_template_attribute_value_ids.add(self.car_color_red)
        with bom_form_car.bom_line_ids.new() as line:
            line.product_id = self.paint._get_variant_for_combination(self.paint_color_blue)
            line.product_uom_id = uom_litre
            line.product_qty = 50
            line.bom_product_template_attribute_value_ids.add(self.car_color_blue)
        with bom_form_car.bom_line_ids.new() as line:
            line.product_id = self.dashboard._get_variant_for_combination(self.dashboard_gps_yes + self.dashboard_color_red)
            line.product_qty = 5
            line.bom_product_template_attribute_value_ids.add(self.car_gps_yes)
            line.bom_product_template_attribute_value_ids.add(self.car_color_red)
        with bom_form_car.bom_line_ids.new() as line:
            line.product_id = self.dashboard._get_variant_for_combination(self.dashboard_gps_yes + self.dashboard_color_blue)
            line.product_qty = 5
            line.bom_product_template_attribute_value_ids.add(self.car_gps_yes)
            line.bom_product_template_attribute_value_ids.add(self.car_color_blue)
        with bom_form_car.bom_line_ids.new() as line:
            line.product_id = self.dashboard._get_variant_for_combination(self.dashboard_gps_no + self.dashboard_color_red)
            line.product_qty = 5
            line.bom_product_template_attribute_value_ids.add(self.car_gps_no)
            line.bom_product_template_attribute_value_ids.add(self.car_color_red)
        with bom_form_car.bom_line_ids.new() as line:
            line.product_id = self.dashboard._get_variant_for_combination(self.dashboard_gps_no + self.dashboard_color_blue)
            line.product_qty = 5
            line.bom_product_template_attribute_value_ids.add(self.car_gps_no)
            line.bom_product_template_attribute_value_ids.add(self.car_color_blue)
        bom_car = bom_form_car.save()

        bom_dashboard = Form(self.env['mrp.bom'])
        bom_dashboard.product_tmpl_id = self.dashboard
        bom_dashboard.product_qty = 2
        with bom_dashboard.bom_line_ids.new() as line:
            line.product_id = self.paint._get_variant_for_combination(self.paint_color_red)
            line.product_uom_id = uom_litre
            line.product_qty = 1
            line.bom_product_template_attribute_value_ids.add(self.dashboard_color_red)
        with bom_dashboard.bom_line_ids.new() as line:
            line.product_id = self.paint._get_variant_for_combination(self.paint_color_blue)
            line.product_uom_id = uom_litre
            line.product_qty = 1
            line.bom_product_template_attribute_value_ids.add(self.dashboard_color_blue)
        with bom_dashboard.bom_line_ids.new() as line:
            line.product_id = self.gps
            line.product_qty = 2
            line.bom_product_template_attribute_value_ids.add(self.dashboard_gps_yes)
        bom_dashboard = bom_dashboard.save()

        blue_car_with_gps = self.car._get_variant_for_combination(self.car_color_blue + self.car_gps_yes)

        report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_car.id, searchQty=1, searchVariant=blue_car_with_gps.id)
        # Two lines. blue dashboard with gps and blue paint.
        self.assertEqual(len(report_values['lines']['components']), 2)

        # 10l of blue paint
        blue_paint = self.paint._get_variant_for_combination(self.paint_color_blue)
        self.assertEqual(blue_paint.id, report_values['lines']['components'][0]['prod_id'])
        self.assertEqual(report_values['lines']['components'][0]['prod_qty'], 10)
        # 1 blue dashboard with GPS
        blue_dashboard_gps = self.dashboard._get_variant_for_combination(self.dashboard_color_blue + self.dashboard_gps_yes)
        self.assertEqual(blue_dashboard_gps.id, report_values['lines']['components'][1]['prod_id'])
        self.assertEqual(report_values['lines']['components'][1]['prod_qty'], 1)
        component = report_values['lines']['components'][1]
        report_values_dashboad = self.env['report.mrp.report_bom_structure']._get_bom(
            component['child_bom'], component['prod_id'], component['prod_qty'],
            component['line_id'], component['level'] + 1)

        self.assertEqual(len(report_values_dashboad['components']), 2)
        self.assertEqual(blue_paint.id, report_values_dashboad['components'][0]['prod_id'])
        self.assertEqual(self.gps.id, report_values_dashboad['components'][1]['prod_id'])

        # 0.5l of paint at price of 20$/litre -> 10$
        self.assertEqual(report_values_dashboad['components'][0]['total'], 10)
        # GPS 700$
        self.assertEqual(report_values_dashboad['components'][1]['total'], 700)

        # Dashboard blue with GPS should have a BoM cost of 710$
        self.assertEqual(report_values['lines']['components'][1]['total'], 710)
        # 10l of paint at price of 20$/litre -> 200$
        self.assertEqual(report_values['lines']['components'][0]['total'], 200)

        # Total cost of blue car with GPS: 10 + 700 + 200 = 910
        self.assertEqual(report_values['lines']['total'], 910)

        red_car_without_gps = self.car._get_variant_for_combination(self.car_color_red + self.car_gps_no)

        report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_car.id, searchQty=1, searchVariant=red_car_without_gps.id)
        # Same math than before but without GPS
        self.assertEqual(report_values['lines']['total'], 210)
Exemple #26
0
    def test_unbuild_with_final_lot(self):
        """ This test creates a MO and then creates 3 unbuild
        orders for the final product. Only the final product is tracked
        by lot. It checks the stock state after each order
        and ensure it is correct.
        """
        mo, bom, p_final, p1, p2 = self.generate_mo(tracking_final='lot')
        self.assertEqual(len(mo), 1, 'MO should have been created')

        lot = self.env['stock.production.lot'].create({
            'name': 'lot1',
            'product_id': p_final.id,
            'company_id': self.env.company.id,
        })

        self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100)
        self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5)
        mo.action_assign()

        produce_form = Form(self.env['mrp.product.produce'].with_context({
            'active_id': mo.id,
            'active_ids': [mo.id],
        }))
        produce_form.qty_producing = 5.0
        produce_form.finished_lot_id = lot
        produce_wizard = produce_form.save()

        produce_wizard.do_produce()

        mo.button_mark_done()
        self.assertEqual(mo.state, 'done', "Production order should be in done state.")

        # Check quantity in stock before unbuild.
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot), 5, 'You should have the 5 final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 80, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 0, 'You should have consumed all the 5 product in stock')

        # ---------------------------------------------------
        #       unbuild
        # ---------------------------------------------------

        # This should fail since we do not choose a lot to unbuild for final product.
        with self.assertRaises(AssertionError):
            x = Form(self.env['mrp.unbuild'])
            x.product_id = p_final
            x.bom_id = bom
            x.product_qty = 3
            x.product_uom_id = self.uom_unit
            unbuild_order = x.save()

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_qty = 3
        x.product_uom_id = self.uom_unit
        x.lot_id = lot
        x.save().action_unbuild()

        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot), 2, 'You should have consumed 3 final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 92, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 3, 'You should have consumed all the 5 product in stock')

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_qty = 2
        x.lot_id = lot
        x.product_uom_id = self.uom_unit
        x.save().action_unbuild()

        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot), 0, 'You should have 0 finalproduct in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 100, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 5, 'You should have consumed all the 5 product in stock')

        x = Form(self.env['mrp.unbuild'])
        x.product_id = p_final
        x.bom_id = bom
        x.product_qty = 5
        x.lot_id = lot
        x.product_uom_id = self.uom_unit
        x.save().action_unbuild()

        self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot, allow_negative=True), -5, 'You should have negative quantity for final product in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p1, self.stock_location), 120, 'You should have 80 products in stock')
        self.assertEqual(self.env['stock.quant']._get_available_quantity(p2, self.stock_location), 10, 'You should have consumed all the 5 product in stock')
    def test_03_invoiced_status(self):
        super_product = self.env['product.product'].create({
            'name':
            'Super Product',
            'invoice_policy':
            'delivery',
        })
        great_product = self.env['product.product'].create({
            'name':
            'Great Product',
            'invoice_policy':
            'delivery',
        })

        so = self.env['sale.order'].create({
            'name':
            'Sale order',
            'partner_id':
            self.partner_a.id,
            'partner_invoice_id':
            self.partner_a.id,
            'order_line': [
                (0, 0, {
                    'name': super_product.name,
                    'product_id': super_product.id,
                    'product_uom_qty': 1,
                    'price_unit': 1,
                }),
                (0, 0, {
                    'name': great_product.name,
                    'product_id': great_product.id,
                    'product_uom_qty': 1,
                    'price_unit': 1,
                }),
            ]
        })
        # Confirm the SO
        so.action_confirm()

        # Deliver one product and create a backorder
        self.assertEqual(
            sum([line.quantity_done for line in so.picking_ids.move_ids]), 0)
        so.picking_ids.move_ids[0].quantity_done = 1
        backorder_wizard_dict = so.picking_ids.button_validate()
        backorder_wizard = Form(
            self.env[backorder_wizard_dict['res_model']].with_context(
                backorder_wizard_dict['context'])).save()
        backorder_wizard.process()
        self.assertEqual(
            sum([line.quantity_done for line in so.picking_ids.move_ids]), 1)

        # Invoice the delivered product
        invoice = so._create_invoices()
        invoice.action_post()
        self.assertEqual(so.invoice_status, 'no')

        # Add delivery fee
        delivery_wizard = Form(
            self.env['choose.delivery.carrier'].with_context({
                'default_order_id':
                so.id,
                'default_carrier_id':
                self.normal_delivery.id
            }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()

        self.assertEqual(so.invoice_status, 'no',
                         'The status should still be "Nothing To Invoice"')
Exemple #28
0
    def test_multi_level_variants2(self):
        """Test skip bom line with same attribute values in bom lines."""

        Product = self.env['product.product']
        ProductAttribute = self.env['product.attribute']
        ProductAttributeValue = self.env['product.attribute.value']
        MrpProduction = self.env['mrp.production']

        # Product Attribute
        att_color = ProductAttribute.create({'name': 'Color'})
        att_size = ProductAttribute.create({'name': 'size'})

        # Product Attribute color Value
        att_color_red = ProductAttributeValue.create({'name': 'red', 'attribute_id': att_color.id})
        att_color_blue = ProductAttributeValue.create({'name': 'blue', 'attribute_id': att_color.id})
        # Product Attribute size Value
        att_size_big = ProductAttributeValue.create({'name': 'big', 'attribute_id': att_size.id})
        att_size_medium = ProductAttributeValue.create({'name': 'medium', 'attribute_id': att_size.id})

        # Create Template Product
        product_template = self.env['product.template'].create({
            'name': 'Sofa',
            'attribute_line_ids': [(0, 0, {
                    'attribute_id': att_color.id,
                    'value_ids': [(6, 0, [att_color_red.id, att_color_blue.id])]
                }), (0, 0, {
                    'attribute_id': att_size.id,
                    'value_ids': [(6, 0, [att_size_big.id, att_size_medium.id])]
                })]
        })

        # Create components Of BOM
        product_A = Product.create({
            'name': 'Wood'})
        product_B = Product.create({
            'name': 'Clothes'})

        # Create BOM
        self.env['mrp.bom'].create({
            'product_tmpl_id': product_template.id,
            'product_qty': 1.0,
            'type': 'normal',
            'bom_line_ids': [(0, 0, {
                    'product_id': product_A.id,
                    'product_qty': 1,
                    'attribute_value_ids': [(4, att_color_red.id), (4, att_color_blue.id), (4, att_size_big.id)],
                }), (0, 0, {
                    'product_id': product_B.id,
                    'product_qty': 1,
                    'attribute_value_ids': [(4, att_color_red.id), (4, att_color_blue.id)]
                })]
        })

        combination = {(att_color_red, att_size_big): [product_A.id, product_B.id] , (att_color_red, att_size_medium): [product_B.id] , (att_color_blue, att_size_big):[product_A.id, product_B.id], (att_color_blue, att_size_medium): [product_B.id]}

        # Create production order for all variants.
        for comb in combination.keys():
            consu_product_ids = combination[comb]
            product = product_template.product_variant_ids.filtered(lambda x:  all(value in comb for value in x.attribute_value_ids))
            mrp_order_form = Form(self.env['mrp.production'])
            mrp_order_form.product_id = product
            mrp_order = mrp_order_form.save()

            # Check consumed materials in production order.
            self.assertEqual(mrp_order.move_raw_ids.mapped('product_id').ids, consu_product_ids)
Exemple #29
0
    def test_at_cost(self):
        """ Test vendor bill at cost for product based on ordered and delivered quantities. """
        # create SO line and confirm SO (with only one line)
        sale_order_line1 = self.env['sale.order.line'].create({
            'name':
            self.company_data['product_order_cost'].name,
            'product_id':
            self.company_data['product_order_cost'].id,
            'product_uom_qty':
            2,
            'qty_delivered':
            1,
            'product_uom':
            self.company_data['product_order_cost'].uom_id.id,
            'price_unit':
            self.company_data['product_order_cost'].list_price,
            'order_id':
            self.sale_order.id,
        })
        sale_order_line1.product_id_change()
        sale_order_line2 = self.env['sale.order.line'].create({
            'name':
            self.company_data['product_delivery_cost'].name,
            'product_id':
            self.company_data['product_delivery_cost'].id,
            'product_uom_qty':
            4,
            'qty_delivered':
            1,
            'product_uom':
            self.company_data['product_delivery_cost'].uom_id.id,
            'price_unit':
            self.company_data['product_delivery_cost'].list_price,
            'order_id':
            self.sale_order.id,
        })
        sale_order_line2.product_id_change()

        self.sale_order.onchange_partner_id()
        self.sale_order._compute_tax_id()
        self.sale_order.action_confirm()

        # create invoice lines and validate it
        move_form = Form(self.AccountMove)
        move_form.partner_id = self.partner_a
        with move_form.line_ids.new() as line_form:
            line_form.product_id = self.company_data['product_order_cost']
            line_form.quantity = 3.0
            line_form.analytic_account_id = self.analytic_account
        with move_form.line_ids.new() as line_form:
            line_form.product_id = self.company_data['product_delivery_cost']
            line_form.quantity = 3.0
            line_form.analytic_account_id = self.analytic_account
        invoice_a = move_form.save()
        invoice_a.action_post()

        sale_order_line3 = self.sale_order.order_line.filtered(
            lambda sol: sol != sale_order_line1 and sol.product_id == self.
            company_data['product_order_cost'])
        sale_order_line4 = self.sale_order.order_line.filtered(
            lambda sol: sol != sale_order_line2 and sol.product_id == self.
            company_data['product_delivery_cost'])

        self.assertTrue(
            sale_order_line3,
            "A new sale line should have been created with ordered product")
        self.assertTrue(
            sale_order_line4,
            "A new sale line should have been created with delivered product")
        self.assertEqual(
            len(self.sale_order.order_line), 4,
            "There should be 4 lines on the SO (2 vendor bill lines created)")
        self.assertEqual(
            len(self.sale_order.order_line.filtered(
                lambda sol: sol.is_expense)), 2,
            "There should be 4 lines on the SO (2 vendor bill lines created)")

        self.assertEqual(
            (sale_order_line3.price_unit, sale_order_line3.qty_delivered,
             sale_order_line3.product_uom_qty, sale_order_line3.qty_invoiced),
            (self.company_data['product_order_cost'].standard_price, 3, 0, 0),
            'Sale line is wrong after confirming vendor invoice')
        self.assertEqual(
            (sale_order_line4.price_unit, sale_order_line4.qty_delivered,
             sale_order_line4.product_uom_qty, sale_order_line4.qty_invoiced),
            (self.company_data['product_delivery_cost'].standard_price, 3, 0,
             0), 'Sale line is wrong after confirming vendor invoice')

        self.assertEqual(
            sale_order_line3.qty_delivered_method, 'analytic',
            "Delivered quantity of 'expense' SO line should be computed by analytic amount"
        )
        self.assertEqual(
            sale_order_line4.qty_delivered_method, 'analytic',
            "Delivered quantity of 'expense' SO line should be computed by analytic amount"
        )

        # create second invoice lines and validate it
        move_form = Form(self.AccountMove)
        move_form.partner_id = self.partner_a
        with move_form.line_ids.new() as line_form:
            line_form.product_id = self.company_data['product_order_cost']
            line_form.quantity = 2.0
            line_form.analytic_account_id = self.analytic_account
        with move_form.line_ids.new() as line_form:
            line_form.product_id = self.company_data['product_delivery_cost']
            line_form.quantity = 2.0
            line_form.analytic_account_id = self.analytic_account
        invoice_b = move_form.save()
        invoice_b.action_post()

        sale_order_line5 = self.sale_order.order_line.filtered(
            lambda sol: sol != sale_order_line1 and sol != sale_order_line3 and
            sol.product_id == self.company_data['product_order_cost'])
        sale_order_line6 = self.sale_order.order_line.filtered(
            lambda sol: sol != sale_order_line2 and sol != sale_order_line4 and
            sol.product_id == self.company_data['product_delivery_cost'])

        self.assertTrue(
            sale_order_line5,
            "A new sale line should have been created with ordered product")
        self.assertTrue(
            sale_order_line6,
            "A new sale line should have been created with delivered product")

        self.assertEqual(
            len(self.sale_order.order_line), 6,
            "There should be still 4 lines on the SO, no new created")
        self.assertEqual(
            len(self.sale_order.order_line.filtered(
                lambda sol: sol.is_expense)), 4,
            "There should be still 2 expenses lines on the SO")

        self.assertEqual(
            (sale_order_line5.price_unit, sale_order_line5.qty_delivered,
             sale_order_line5.product_uom_qty, sale_order_line5.qty_invoiced),
            (self.company_data['product_order_cost'].standard_price, 2, 0, 0),
            'Sale line 5 is wrong after confirming 2e vendor invoice')
        self.assertEqual(
            (sale_order_line6.price_unit, sale_order_line6.qty_delivered,
             sale_order_line6.product_uom_qty, sale_order_line6.qty_invoiced),
            (self.company_data['product_delivery_cost'].standard_price, 2, 0,
             0), 'Sale line 6 is wrong after confirming 2e vendor invoice')
    def test_shipping_cost(self):
        # Free delivery should not be taken into account when checking for minimum required threshold
        p_minimum_threshold_free_delivery = self.env[
            'sale.coupon.program'].create({
                'name': 'free shipping if > 872 tax exl',
                'promo_code_usage': 'no_code_needed',
                'reward_type': 'free_shipping',
                'program_type': 'promotion_program',
                'rule_minimum_amount': 872,
            })
        p_minimum_threshold_discount = self.env['sale.coupon.program'].create({
            'name':
            '10% reduction if > 872 tax exl',
            'promo_code_usage':
            'no_code_needed',
            'reward_type':
            'discount',
            'program_type':
            'promotion_program',
            'discount_type':
            'percentage',
            'discount_percentage':
            10.0,
            'rule_minimum_amount':
            872,
        })
        order = self.empty_order
        self.iPadMini.taxes_id = self.tax_10pc_incl
        sol1 = self.env['sale.order.line'].create({
            'product_id': self.iPadMini.id,
            'name': 'Large Cabinet',
            'product_uom_qty': 3.0,
            'order_id': order.id,
        })
        order.recompute_coupon_lines()
        self.assertEqual(
            len(order.order_line.ids), 2,
            "We should get the 10% discount line since we bought 872.73$")
        order.carrier_id = self.env['delivery.carrier'].search([])[1]

        # I add delivery cost in Sales order
        delivery_wizard = Form(
            self.env['choose.delivery.carrier'].with_context({
                'default_order_id':
                order.id,
                'default_carrier_id':
                self.env['delivery.carrier'].search([])[1]
            }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()

        order.recompute_coupon_lines()
        self.assertEqual(
            len(order.order_line.ids), 3,
            "We should get the delivery line but not the free delivery since we are below 872.73$ with the 10% discount"
        )

        p_minimum_threshold_free_delivery.sequence = 10
        (order.order_line - sol1).unlink()
        # I add delivery cost in Sales order
        delivery_wizard = Form(
            self.env['choose.delivery.carrier'].with_context({
                'default_order_id':
                order.id,
                'default_carrier_id':
                self.env['delivery.carrier'].search([])[1]
            }))
        choose_delivery_carrier = delivery_wizard.save()
        choose_delivery_carrier.button_confirm()
        order.recompute_coupon_lines()
        self.assertEqual(
            len(order.order_line.ids), 4,
            "We should get both promotion line since the free delivery will be applied first and won't change the SO total"
        )