Example #1
0
 def test_allocation_request(self):
     """ Create an allocation request """
     # employee should be set to current user
     allocation_form = Form(self.env['hr.leave.allocation'].sudo(
         self.user_employee))
     allocation_form.holiday_status_id = self.holidays_type_1
     allocation = allocation_form.save()
 def _create_invoice_from_file(self, attachment):
     self = self.with_context(default_journal_id=self.journal_id.id)
     invoice_form = Form(self.env['account.invoice'],
                         view='account.invoice_supplier_form')
     invoice = invoice_form.save()
     attachment.write({
         'res_model': 'account.invoice',
         'res_id': invoice.id
     })
     invoice.message_post(attachment_ids=[attachment.id])
     return invoice
Example #3
0
    def test_state(self):
        # In order to test Confirm Draft Invoice wizard I create an invoice
        # and confirm it with this wizard
        f = Form(self.env['account.invoice'])
        f.partner_id = self.env.ref('base.res_partner_12')
        with f.invoice_line_ids.new() as l:
            l.product_id = self.env.ref('product.product_product_3')
        invoice = f.save()

        # I check that Initially customer invoice state is "Draft"
        self.assertEqual(invoice.state, 'draft')

        # I called the "Confirm Draft Invoices" wizard
        w = Form(self.env['account.invoice.confirm']).save()
        # I clicked on Confirm Invoices Button
        w.with_context(
            active_model='account.invoice',
            active_id=invoice.id,
            active_ids=invoice.ids,
            type='out_invoice',
        ).invoice_confirm()

        # I check that customer invoice state is "Open"
        self.assertEqual(invoice.state, 'open')

        # I check the journal associated and put this journal as not
        moves = self.env['account.move.line'].search([('invoice_id', '=',
                                                       invoice.id)])
        self.assertGreater(len(moves), 0, 'You should have multiple moves')
        moves[0].journal_id.write({'update_posted': True})

        # I cancelled this open invoice using the button on invoice
        invoice.action_invoice_cancel()
        # I check that customer invoice is in the cancel state
        self.assertEqual(invoice.state, 'cancel')
    def test_attendance_on_morning(self):
        calendar = self.env['resource.calendar'].create({
            'name':
            'Morning only',
            'attendance_ids': [(5, 0, 0),
                               (0, 0, {
                                   'name': 'Monday All day',
                                   'hour_from': 8,
                                   'hour_to': 16,
                                   'day_period': 'morning',
                                   'dayofweek': '0',
                               })],
        })
        employee = self.employee_emp
        employee.resource_calendar_id = calendar
        with Form(self.env['hr.leave']) as leave_form:
            leave_form.employee_id = employee
            leave_form.holiday_status_id = self.leave_type
            leave_form.request_date_from = date(2019, 9, 2)
            leave_form.request_date_to = date(2019, 9, 2)
            leave_form.request_unit_half = True
            # Ask for morning
            leave_form.request_date_from_period = 'am'

            self.assertEqual(leave_form.number_of_days_display, 1)
            self.assertEqual(leave_form.number_of_hours_display, 8)

            # Ask for afternoon
            leave_form.request_date_from_period = 'pm'

            self.assertEqual(leave_form.number_of_days_display, 1)
            self.assertEqual(leave_form.number_of_hours_display, 8)
    def test_attendance_previous_day(self):
        calendar = self.env['resource.calendar'].create({
            'name':
            'auto next day',
            'attendance_ids': [(5, 0, 0),
                               (0, 0, {
                                   'name': 'monday morning',
                                   'hour_from': 8,
                                   'hour_to': 12,
                                   'day_period': 'morning',
                                   'dayofweek': '0',
                               })]
        })
        employee = self.employee_emp
        employee.resource_calendar_id = calendar

        with Form(self.env['hr.leave']) as leave_form:
            leave_form.employee_id = employee
            leave_form.holiday_status_id = self.leave_type
            leave_form.request_date_from = date(2019, 9, 3)
            leave_form.request_date_to = date(2019, 9, 3)
            leave_form.request_unit_half = True
            leave_form.request_date_from_period = 'am'

            self.assertEqual(leave_form.number_of_days_display, 0)
            self.assertEqual(leave_form.number_of_hours_display, 0)
            self.assertEqual(leave_form.date_from,
                             datetime(2019, 9, 3, 6, 0, 0))
            self.assertEqual(leave_form.date_to,
                             datetime(2019, 9, 3, 10, 0, 0))
Example #6
0
 def test_invoice_currency_onchange(self):
     self_ctx = self.env['account.invoice'].with_context(type='out_invoice')
     with Form(self_ctx, view='account.invoice_form') as invoice_form:
         invoice_form.partner_id = self.env.user.partner_id
         with invoice_form.invoice_line_ids.new() as invoice_line_form:
             invoice_line_form.product_id = self.apples_product
         # Check onchange keep price_unit if currency not changed
         self.assertEqual(invoice_line_form.price_unit, 10)
         invoice_form.currency_id = self.half_currency
         with invoice_form.invoice_line_ids.new() as invoice_line_form:
             invoice_line_form.product_id = self.apples_product
         # Check onchange gives converted price with custom currency
         self.assertEqual(invoice_line_form.price_unit, 20)
Example #7
0
    def test_06_differed_schedule_date(self):
        warehouse = self.env['stock.warehouse'].search([], limit=1)
        with Form(warehouse) as w:
            w.reception_steps = 'three_steps'
        po_form = Form(self.env['purchase.order'])
        po_form.partner_id = self.partner_id
        with po_form.order_line.new() as line:
            line.product_id = self.product_id_1
            line.date_planned = datetime.today()
            line.product_qty = 1.0
        with po_form.order_line.new() as line:
            line.product_id = self.product_id_1
            line.date_planned = datetime.today() + timedelta(days=7)
            line.product_qty = 1.0
        po = po_form.save()
        po.button_approve()

        po.picking_ids.move_line_ids.write({'qty_done': 1.0})
        po.picking_ids.action_done()
        pickings = self.env['stock.picking'].search([('group_id', '=',
                                                      po.group_id.id)])
        for picking in pickings:
            self.assertEqual(picking.scheduled_date.date(), date.today())
    def test_multiple_attendance_on_morning(self):
        calendar = self.env['resource.calendar'].create({
            'name':
            'multi morning',
            'attendance_ids': [(5, 0, 0),
                               (0, 0, {
                                   'name': 'monday morning 1',
                                   'hour_from': 8,
                                   'hour_to': 10,
                                   'day_period': 'morning',
                                   'dayofweek': '0',
                               }),
                               (0, 0, {
                                   'name': 'monday morning 2',
                                   'hour_from': 10.25,
                                   'hour_to': 12.25,
                                   'day_period': 'morning',
                                   'dayofweek': '0',
                               }),
                               (0, 0, {
                                   'name': 'monday afternoon',
                                   'hour_from': 13,
                                   'hour_to': 17,
                                   'day_period': 'afternoon',
                                   'dayofweek': '0',
                               })]
        })
        employee = self.employee_emp
        employee.resource_calendar_id = calendar

        with Form(self.env['hr.leave']) as leave_form:
            leave_form.employee_id = employee
            leave_form.holiday_status_id = self.leave_type
            leave_form.request_date_from = date(2019, 9, 2)
            leave_form.request_date_to = date(2019, 9, 2)
            leave_form.request_unit_half = True
            leave_form.request_date_from_period = 'am'

            self.assertEqual(leave_form.number_of_days_display, .5)
            self.assertEqual(leave_form.number_of_hours_display, 4)

            leave_form.request_date_from_period = 'pm'

            self.assertEqual(leave_form.number_of_days_display, .5)
            self.assertEqual(leave_form.number_of_hours_display, 4)
Example #9
0
    def test_basic(self):
        env = self.env(context=dict(self.env.context, journal_type='bank'))

        # select the period and journal for the bank statement
        journal = env['account.bank.statement'].with_context(
            date=time.strftime("%Y/%m/%d"),  # ???
        )._default_journal()
        self.assertTrue(journal, 'Journal has not been selected')

        f = Form(env['account.bank.statement'])
        # necessary as there may be existing bank statements with a non-zero
        # closing balance which will be used to initialise this one.
        f.balance_start = 0.0
        f.balance_end_real = 0.0
        with f.line_ids.new() as line:
            line.name = 'EXT001'
            line.amount = 1000
            line.partner_id = env.ref('base.res_partner_4')

        statement_id = f.save()

        # process the bank statement line
        account = env['account.account'].create({
            'name':
            'toto',
            'code':
            'bidule',
            'user_type_id':
            env.ref('account.data_account_type_fixed_assets').id
        })
        statement_id.line_ids[0].process_reconciliation(
            new_aml_dicts=[{
                'credit': 1000,
                'debit': 0,
                'name': 'toto',
                'account_id': account.id,
            }])

        with Form(statement_id) as f:
            # modify the bank statement and set the Ending Balance.
            f.balance_end_real = 1000.0

        # confirm the bank statement using Validate button
        statement_id.button_confirm_bank()

        self.assertEqual(statement_id.state, 'confirm')
 def _create_invoice_line(self, amount, partner, type):
     ''' Create an invoice on the fly.'''
     self_ctx = self.env['account.invoice'].with_context(type=type)
     journal_id = self_ctx._default_journal().id
     self_ctx = self_ctx.with_context(journal_id=journal_id)
     view = type in (
         'in_invoice', 'in_refund'
     ) and 'account.invoice_supplier_form' or 'account.invoice_form'
     with Form(self_ctx, view=view) as invoice_form:
         invoice_form.partner_id = partner
         with invoice_form.invoice_line_ids.new() as invoice_line_form:
             invoice_line_form.name = 'xxxx'
             invoice_line_form.quantity = 1
             invoice_line_form.price_unit = amount
             invoice_line_form.invoice_line_tax_ids.clear()
     invoice = invoice_form.save()
     invoice.action_invoice_open()
     lines = invoice.move_id.line_ids
     return lines.filtered(lambda l: l.account_id == invoice.account_id)
    def test_no_attendances(self):
        calendar = self.env['resource.calendar'].create({
            'name':
            'No Attendances',
            'attendance_ids': [(5, 0, 0)],
        })
        employee = self.employee_emp
        employee.resource_calendar_id = calendar

        with Form(self.env['hr.leave']) as leave_form:
            leave_form.employee_id = employee
            leave_form.holiday_status_id = self.leave_type
            leave_form.request_date_from = date(2019, 9, 2)
            leave_form.request_date_to = date(2019, 9, 2)
            leave_form.request_unit_half = True
            leave_form.request_date_from_period = 'am'

            self.assertEqual(leave_form.number_of_days_display, 0)
            self.assertEqual(leave_form.number_of_hours_display, 0)
Example #12
0
 def test_department_leave(self):
     """ Create a department leave """
     self.employee_hrmanager.write({'department_id': self.hr_dept.id})
     self.assertFalse(self.env['hr.leave'].search([
         ('employee_id', 'in', self.hr_dept.member_ids.ids)
     ]))
     leave_form = Form(self.env['hr.leave'].sudo(self.user_hrmanager))
     leave_form.holiday_type = 'department'
     leave_form.department_id = self.hr_dept
     leave_form.holiday_status_id = self.holidays_type_1
     leave = leave_form.save()
     leave.action_approve()
     member_ids = self.hr_dept.member_ids.ids
     self.assertEqual(
         self.env['hr.leave'].search_count([('employee_id', 'in',
                                             member_ids)]), len(member_ids),
         "Leave should be created for members of department")
    def test_onchange_taxes_2(self):
        '''
        Test the amount of tax account.move.line is adapted when editing the account.move.line amount.
        This test uses the following scenario:
            - Create manually a debit line of 1000 having a tax.
            - Assume a line containing the tax amount is created automatically.
            - Set the debit amount to 2000 in the first created line.
            - Assume the line containing the tax amount has been updated automatically.
            - Create manually a credit line to balance the two previous lines.
            - Save the move.

        tax = 10%

        Name            | Debit     | Credit    | Tax_ids       | Tax_line_id's name
        ----------------|-----------|-----------|---------------|-------------------
        debit_line_1    | 2000      |           | tax           |
        tax_line        | 200       |           |               | tax_line
        debit_line_1    |           | 2200      |               |
        '''
        move_form = Form(self.env['account.move'],
                         view='account.view_move_form')
        move_form.ref = 'azerty'
        move_form.journal_id = self.journal

        # Create a new account.move.line with debit amount.
        with move_form.line_ids.new() as debit_line:
            debit_line.name = 'debit_line_1'
            debit_line.account_id = self.account
            debit_line.debit = 1000
            debit_line.tax_ids.clear()
            debit_line.tax_ids.add(self.percent_tax)

            self.assertTrue(debit_line.recompute_tax_line)

            debit_line.debit = 2000

            self.assertTrue(debit_line.recompute_tax_line)

        # Create a third account.move.line with credit amount.
        with move_form.line_ids.new() as credit_line:
            credit_line.name = 'credit_line_1'
            credit_line.account_id = self.account
            credit_line.credit = 2200

        move = move_form.save()

        self.assertRecordValues(move.line_ids, [
            {
                'name': 'credit_line_1',
                'debit': 0.0,
                'credit': 2200.0,
                'tax_ids': [],
                'tax_line_id': False
            },
            {
                'name': 'tax_line',
                'debit': 200.0,
                'credit': 0.0,
                'tax_ids': [],
                'tax_line_id': self.percent_tax.id
            },
            {
                'name': 'debit_line_1',
                'debit': 2000.0,
                'credit': 0.0,
                'tax_ids': [self.percent_tax.id],
                'tax_line_id': False
            },
        ])
    def test_onchange_taxes_3(self):
        '''
        Test the amount of tax account.move.line is still editable manually.
        Test the amount of tax account.move.line is cumulative for the same tax.
        This test uses the following scenario:
            - Create manually a debit line of 1000 having a tax.
            - Assume a line containing the tax amount is created automatically.
            - Edit the tax line amount of the auto-generated line by adding 5.
            - Create manually a credit line to balance the two previous lines.
            - Save the move.
            - Edit the move.
            - Create manually a debit line of 2000 having the same tax.
            - Assume the line containing the tax amount has been updated (no new line created).
            - Create manually a credit line to balance the four previous lines.
            - Save the move.

        tax = 10%

        Name            | Debit     | Credit    | Tax_ids       | Tax_line_id's name
        ----------------|-----------|-----------|---------------|-------------------
        debit_line_1    | 1000      |           | tax           |
        tax_line        | 300       |           |               | tax_line
        credit_line_1   |           | 1105      |               |
        debit_line_2    | 2000      |           | tax           |
        credit_line_2   |           | 2195      |               |
        '''
        move_form = Form(self.env['account.move'],
                         view='account.view_move_form')
        move_form.ref = 'azerty'
        move_form.journal_id = self.journal

        # Create a new account.move.line with debit amount.
        with move_form.line_ids.new() as debit_line:
            debit_line.name = 'debit_line_1'
            debit_line.account_id = self.account
            debit_line.debit = 1000
            debit_line.tax_ids.clear()
            debit_line.tax_ids.add(self.percent_tax)

            self.assertTrue(debit_line.recompute_tax_line)

        # Edit the tax account.move.line
        with move_form.line_ids.edit(index=1) as tax_line:
            tax_line.debit = 105  # Was 100

        # Create a third account.move.line with credit amount.
        with move_form.line_ids.new() as credit_line:
            credit_line.name = 'credit_line_1'
            credit_line.account_id = self.account
            credit_line.credit = 1105

        move = move_form.save()

        move_form = Form(move, view='account.view_move_form')
        # Create a new account.move.line with debit amount.
        with move_form.line_ids.new() as debit_line2:
            debit_line2.name = 'debit_line_2'
            debit_line2.account_id = self.account
            debit_line2.debit = 2000
            debit_line2.tax_ids.clear()
            debit_line2.tax_ids.add(self.percent_tax)

            self.assertTrue(debit_line2.recompute_tax_line)

        with move_form.line_ids.new() as credit_line2:
            credit_line2.name = 'credit_line_2'
            credit_line2.account_id = self.account
            credit_line2.credit = 2195

        move = move_form.save()

        self.assertRecordValues(move.line_ids, [
            {
                'name': 'credit_line_2',
                'debit': 0.0,
                'credit': 2195.0,
                'tax_ids': [],
                'tax_line_id': False
            },
            {
                'name': 'debit_line_2',
                'debit': 2000.0,
                'credit': 0.0,
                'tax_ids': [self.percent_tax.id],
                'tax_line_id': False
            },
            {
                'name': 'credit_line_1',
                'debit': 0.0,
                'credit': 1105.0,
                'tax_ids': [],
                'tax_line_id': False
            },
            {
                'name': 'tax_line',
                'debit': 300.0,
                'credit': 0.0,
                'tax_ids': [],
                'tax_line_id': self.percent_tax.id
            },
            {
                'name': 'debit_line_1',
                'debit': 1000.0,
                'credit': 0.0,
                'tax_ids': [self.percent_tax.id],
                'tax_line_id': False
            },
        ])
Example #15
0
    def test_sale_mrp_pickings(self):
        """ Test sale of multiple mrp products in MTO
        to avoid generating multiple deliveries
        to the customer location
        """

        # Create warehouse
        self.customer_location = self.env['ir.model.data'].xmlid_to_res_id(
            'stock.stock_location_customers')
        warehouse_form = Form(self.env['stock.warehouse'])
        warehouse_form.name = 'Test Warehouse'
        warehouse_form.code = 'TWH'
        self.warehouse = warehouse_form.save()

        self.uom_unit = self.env.ref('uom.product_uom_unit')

        # Create raw product for manufactured product
        product_form = Form(self.env['product.product'])
        product_form.name = 'Raw Stick'
        product_form.type = 'product'
        product_form.uom_id = self.uom_unit
        product_form.uom_po_id = self.uom_unit
        self.raw_product = product_form.save()

        # Create manufactured product
        product_form = Form(self.env['product.product'])
        product_form.name = 'Stick'
        product_form.uom_id = self.uom_unit
        product_form.uom_po_id = self.uom_unit
        product_form.type = 'product'
        product_form.route_ids.clear()
        product_form.route_ids.add(self.warehouse.manufacture_pull_id.route_id)
        product_form.route_ids.add(self.warehouse.mto_pull_id.route_id)
        self.finished_product = product_form.save()

        # Create manifactured product which uses another manifactured
        product_form = Form(self.env['product.product'])
        product_form.name = 'Arrow'
        product_form.type = 'product'
        product_form.route_ids.clear()
        product_form.route_ids.add(self.warehouse.manufacture_pull_id.route_id)
        product_form.route_ids.add(self.warehouse.mto_pull_id.route_id)
        self.complex_product = product_form.save()

        ## Create raw product for manufactured product
        product_form = Form(self.env['product.product'])
        product_form.name = 'Raw Iron'
        product_form.type = 'product'
        product_form.uom_id = self.uom_unit
        product_form.uom_po_id = self.uom_unit
        self.raw_product_2 = product_form.save()

        # Create bom for manufactured product
        bom_product_form = Form(self.env['mrp.bom'])
        bom_product_form.product_id = self.finished_product
        bom_product_form.product_tmpl_id = self.finished_product.product_tmpl_id
        bom_product_form.product_qty = 1.0
        bom_product_form.type = 'normal'
        with bom_product_form.bom_line_ids.new() as bom_line:
            bom_line.product_id = self.raw_product
            bom_line.product_qty = 2.0

        self.bom = bom_product_form.save()

        ## Create bom for manufactured product
        bom_product_form = Form(self.env['mrp.bom'])
        bom_product_form.product_id = self.complex_product
        bom_product_form.product_tmpl_id = self.complex_product.product_tmpl_id
        with bom_product_form.bom_line_ids.new() as line:
            line.product_id = self.finished_product
            line.product_qty = 1.0
        with bom_product_form.bom_line_ids.new() as line:
            line.product_id = self.raw_product_2
            line.product_qty = 1.0

        self.complex_bom = bom_product_form.save()

        with Form(self.warehouse) as warehouse:
            warehouse.manufacture_steps = 'pbm_sam'

        so_form = Form(self.env['sale.order'])
        so_form.partner_id = self.env.ref('base.res_partner_4')
        with so_form.order_line.new() as line:
            line.product_id = self.complex_product
            line.price_unit = 1
            line.product_uom_qty = 1
        with so_form.order_line.new() as line:
            line.product_id = self.finished_product
            line.price_unit = 1
            line.product_uom_qty = 1
        sale_order_so0 = so_form.save()

        sale_order_so0.action_confirm()

        pickings = sale_order_so0.picking_ids

        # One delivery...
        self.assertEqual(len(pickings), 1)

        # ...with two products
        move_lines = pickings[0].move_lines
        self.assertEqual(len(move_lines), 2)
Example #16
0
    def test_sale_mrp(self):
        warehouse0 = self.env.ref('stock.warehouse0')
        # In order to test the sale_mrp module in OpenERP, I start by creating a new product 'Slider Mobile'
        # I define product category Mobile Products Sellable.

        with mute_logger('swerp.tests.common.onchange'):
            # Suppress warning on "Changing your cost method" when creating a
            # product category
            pc = Form(self.env['product.category'])
        pc.name = 'Mobile Products Sellable'
        product_category_allproductssellable0 = pc.save()

        uom_unit = self.env.ref('uom.product_uom_unit')

        self.assertIn("seller_ids", self.env['product.template'].fields_get())

        # I define product for Slider Mobile.
        product = Form(self.env['product.template'])

        product.categ_id = product_category_allproductssellable0
        product.list_price = 200.0
        product.name = 'Slider Mobile'
        product.standard_price = 189.0
        product.type = 'product'
        product.uom_id = uom_unit
        product.uom_po_id = uom_unit
        product.route_ids.clear()
        product.route_ids.add(warehouse0.manufacture_pull_id.route_id)
        product.route_ids.add(warehouse0.mto_pull_id.route_id)
        product_template_slidermobile0 = product.save()

        with Form(self.env['mrp.bom']) as bom:
            bom.product_tmpl_id = product_template_slidermobile0

        # I create a sale order for product Slider mobile
        so_form = Form(self.env['sale.order'])
        so_form.partner_id = self.env.ref('base.res_partner_4')
        with so_form.order_line.new() as line:
            line.product_id = product_template_slidermobile0.product_variant_ids
            line.price_unit = 200
            line.product_uom_qty = 500.0
            line.customer_lead = 7.0
        sale_order_so0 = so_form.save()

        # I confirm the sale order
        sale_order_so0.action_confirm()

        # I verify that a manufacturing order has been generated, and that its name and reference are correct
        mo = self.env['mrp.production'].search(
            [('origin', 'like', sale_order_so0.name)], limit=1)
        self.assertTrue(mo, 'Manufacturing order has not been generated')
Example #17
0
    def _import_facturx_invoice(self, tree):
        ''' Extract invoice values from the Factur-x xml tree passed as parameter.

        :param tree: The tree of the Factur-x xml file.
        :return: A dictionary containing account.invoice values to create/update it.
        '''
        amount_total_import = None

        # type must be present in the context to get the right behavior of the _default_journal method (account.invoice).
        # journal_id must be present in the context to get the right behavior of the _default_account method (account.invoice.line).
        self_ctx = self.with_context(type='in_invoice')
        journal_id = self_ctx._default_journal().id
        self_ctx = self_ctx.with_context(journal_id=journal_id)

        # self could be a single record (editing) or be empty (new).
        with Form(self_ctx, view='account.invoice_supplier_form') as invoice_form:

            # Partner (first step to avoid warning 'Warning! You must first select a partner.').
            elements = tree.xpath('//ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID', namespaces=tree.nsmap)
            partner = elements and self.env['res.partner'].search([('vat', '=', elements[0].text)], limit=1)
            if not partner:
                elements = tree.xpath('//ram:SellerTradeParty/ram:Name', namespaces=tree.nsmap)
                partner_name = elements and elements[0].text
                partner = elements and self.env['res.partner'].search([('name', 'ilike', partner_name)], limit=1)
            if not partner:
                elements = tree.xpath('//ram:SellerTradeParty//ram:URIID[@schemeID=\'SMTP\']', namespaces=tree.nsmap)
                partner = elements and self.env['res.partner'].search([('email', '=', elements[0].text)], limit=1)
            if partner:
                invoice_form.partner_id = partner

            # Reference.
            elements = tree.xpath('//rsm:ExchangedDocument/ram:ID', namespaces=tree.nsmap)
            if elements:
                invoice_form.reference = elements[0].text

            # Name.
            elements = tree.xpath('//ram:BuyerOrderReferencedDocument/ram:IssuerAssignedID', namespaces=tree.nsmap)
            if elements:
                invoice_form.name = elements[0].text

            # Comment.
            elements = tree.xpath('//ram:IncludedNote/ram:Content', namespaces=tree.nsmap)
            if elements:
                invoice_form.comment = elements[0].text

            # Refund type.
            # There is two modes to handle refund in Factur-X:
            # a) type_code == 380 for invoice, type_code == 381 for refund, all positive amounts.
            # b) type_code == 380, negative amounts in case of refund.
            # To handle both, we consider the 'a' mode and switch to 'b' if a negative amount is encountered.
            elements = tree.xpath('//rsm:ExchangedDocument/ram:TypeCode', namespaces=tree.nsmap)
            type_code = elements[0].text
            refund_sign = type_code == '380' and 1 or -1

            # Total amount.
            elements = tree.xpath('//ram:GrandTotalAmount', namespaces=tree.nsmap)
            if elements:
                total_amount = float(elements[0].text)

                # Handle 'a & b' refund mode.
                if (total_amount < 0 and type_code == '380') or type_code == '381':
                    refund_sign = -1

                # Currency.
                if elements[0].attrib.get('currencyID'):
                    currency_str = elements[0].attrib['currencyID']
                    currency = self.env.ref('base.%s' % currency_str.upper(), raise_if_not_found=False)
                    if currency != self.env.user.company_id.currency_id and currency.active:
                        invoice_form.currency_id = currency

                    # Store xml total amount.
                    amount_total_import = total_amount * refund_sign

            # Date.
            elements = tree.xpath('//rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString', namespaces=tree.nsmap)
            if elements:
                date_str = elements[0].text
                date_obj = datetime.strptime(date_str, DEFAULT_FACTURX_DATE_FORMAT)
                invoice_form.date_invoice = date_obj.strftime(DEFAULT_SERVER_DATE_FORMAT)

            # Due date.
            elements = tree.xpath('//ram:SpecifiedTradePaymentTerms/ram:DueDateDateTime/udt:DateTimeString', namespaces=tree.nsmap)
            if elements:
                date_str = elements[0].text
                date_obj = datetime.strptime(date_str, DEFAULT_FACTURX_DATE_FORMAT)
                date_due = date_obj.strftime(DEFAULT_SERVER_DATE_FORMAT)
                if date_due:
                    invoice_form.payment_term_id = self.env['account.payment.term']
                    invoice_form.date_due = date_due

            # Invoice lines.
            elements = tree.xpath('//ram:IncludedSupplyChainTradeLineItem', namespaces=tree.nsmap)
            if elements:
                for element in elements:
                    with invoice_form.invoice_line_ids.new() as invoice_line_form:

                        # Sequence.
                        line_elements = element.xpath('.//ram:AssociatedDocumentLineDocument/ram:LineID', namespaces=tree.nsmap)
                        if line_elements:
                            invoice_line_form.sequence = int(line_elements[0].text)

                        # Product.
                        line_elements = element.xpath('.//ram:SpecifiedTradeProduct/ram:Name', namespaces=tree.nsmap)
                        if line_elements:
                            invoice_line_form.name = line_elements[0].text
                        line_elements = element.xpath('.//ram:SpecifiedTradeProduct/ram:SellerAssignedID', namespaces=tree.nsmap)
                        if line_elements and line_elements[0].text:
                            product = self.env['product.product'].search([('default_code', '=', line_elements[0].text)])
                            if product:
                                invoice_line_form.product_id = product
                        if not invoice_line_form.product_id:
                            line_elements = element.xpath('.//ram:SpecifiedTradeProduct/ram:GlobalID', namespaces=tree.nsmap)
                            if line_elements and line_elements[0].text:
                                product = self.env['product.product'].search([('barcode', '=', line_elements[0].text)])
                                if product:
                                    invoice_line_form.product_id = product

                        # Quantity.
                        line_elements = element.xpath('.//ram:SpecifiedLineTradeDelivery/ram:BilledQuantity', namespaces=tree.nsmap)
                        if line_elements:
                            invoice_line_form.quantity = float(line_elements[0].text)

                        # Price Unit.
                        line_elements = element.xpath('.//ram:GrossPriceProductTradePrice/ram:ChargeAmount', namespaces=tree.nsmap)
                        if line_elements:
                            invoice_line_form.price_unit = float(line_elements[0].text) / invoice_line_form.quantity
                        else:
                            line_elements = element.xpath('.//ram:NetPriceProductTradePrice/ram:ChargeAmount', namespaces=tree.nsmap)
                            if line_elements:
                                invoice_line_form.price_unit = float(line_elements[0].text) / invoice_line_form.quantity

                        # Discount.
                        line_elements = element.xpath('.//ram:AppliedTradeAllowanceCharge/ram:CalculationPercent', namespaces=tree.nsmap)
                        if line_elements:
                            invoice_line_form.discount = float(line_elements[0].text)

                        # Taxes
                        line_elements = element.xpath('.//ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent', namespaces=tree.nsmap)
                        invoice_line_form.invoice_line_tax_ids.clear()
                        for tax_element in line_elements:
                            percentage = float(tax_element.text)

                            tax = self.env['account.tax'].search([
                                ('company_id', '=', invoice_form.company_id.id),
                                ('amount_type', '=', 'percent'),
                                ('type_tax_use', '=', 'purchase'),
                                ('amount', '=', percentage),
                            ], limit=1)

                            if tax:
                                invoice_line_form.invoice_line_tax_ids.add(tax)
            elif amount_total_import:
                # No lines in BASICWL.
                with invoice_form.invoice_line_ids.new() as invoice_line_form:
                    invoice_line_form.name = invoice_form.comment or '/'
                    invoice_line_form.quantity = 1
                    invoice_line_form.price_unit = amount_total_import

            # Refund.
            invoice_form.type = 'in_refund' if refund_sign == -1 else 'in_invoice'

        return invoice_form.save()