3
votes

I am using odoo 10 and I have two models Order_Line and Products.

OrderLine

class OrderLine(models.Model):
_name = 'order_line'
_description = 'Order Lines'

name = fields.Char()
products = fields.Many2one('amgl.products', String='Products')

Products

class Products(models.Model):
_name = 'products'
_description = 'Products'
    _sql_constraints = [
    ('uniq_poduct_code', 'unique(product_code)', 'Product Code already exists!')
]

name = fields.Char()
product_code = Char()

Now i am trying to create order_line from a csv file and in csv file the customer is providing me 'Product Code' instead of Id. How to handle this that, we use product code and system automatically fills the products associated with that product code.

Note :

Product Code in products table is also unique, so there is no chance of duplicating.

CSV template:

customer/account_number,customer/first_name,customer/last_name,customer/account_type,order/transaction_id,order/products/product_code,order/quantity,order/customer_id/id
3
Could you show the CSV template that you would like to import please?ChesuCR

3 Answers

1
votes

Case 1: there are no products stored in the database with any of the product codes the customer is giving to you

If the product codes haven't been created yet in the database, you should have two CSV files (Products.csv and OrderLine.csv). The first one must have three columns (id, name and product_code). The second one must have three columns too (id, name and products/id). So you would only have to make up a XML ID under the id column in Products.csv and call this XML ID from the respective row of the column products/id of the file OrderLine.csv.

Case 2: the product codes the customer has given to you belong to existing products in the database

Now, the customer has given you product codes of products which already exist in the database. In this case you don't have to create a Products.csv file. You need to know which are the XML IDs of the products which have the product codes the customer gave to you. For that, you can go through the interface of Odoo to the tree view of the model products (if this view doesn't exist, you must create it). Then, you'll have to select all records (click on the number 80 of the top right corner to show more records per page if you need it). Once all of them are selected, click on More button and afterwars on Export. Select the column product_code and name and afterwards proceed. Save the generated CSV file as Products.csv, for example. Open it, you'll see all the XML ID of the exported products (if they hadn't XML ID, after the exportation they'll do -an exportation generates XML ID for each exported record if it doesn't have anyone-). Now, I guess the customer has given you something like a file with columns Name of the order line, Product code, so replace the Product code column values with the respective XML IDs of the products you have just exported. So in the end youu should have one file to import, OrderLine.csv, with id, name and products/id columns.

Case 3: there are some product codes belonging to existing products stored in the database and there are some ones which still don't exist

In this case you will have to combine both cases 1 and 2, first, export the products as described in case 2, and then, create a new one with the products whose code doesn't exist yet, as described in case 1. Then replace the product codes the customer gave to you with the respective ones as described in case 2.

Note: this process will give you a lot of time if you have thousands of records to import and you replace them manually. In this case it is mandatory to create a macro in your CSV editor which does the replacements (with search and replace). For example, with LibreOffice you can do macros with Python.

Example (Case 3)

The customer has given you a file of order lines, with two lines:

  • Name: OL A, Product Code: AAA
  • Name: OL B, Product Code: BBB

You export products from Odoo interface and you get a file with one line:

id,name,product_code __export__.products_a,"Product A","AAA"

You look for the coincidences of the product codes in both files, and do the replacements in a copy of the customer file, so now you have this:

  • Name: OL A, Product Code: __export__.products_a
  • Name: OL B, Product Code: BBB

Then you create a new CSV Products.csv and put in there the products whose product code don't exist yet:

id,name,product_code __import__.products_b,"Product B","BBB"

Now apply the replacements again comparing this new file with the one we had, and you will get this:

  • Name: OL A, Product Code: __export__.products_a
  • Name: OL B, Product Code: __import__.products_b

Convert this file to a right CSV format for Odoo, and save it as OrderLine.csv:

id,name,products/id __import__.order_line_1,"OL A",__export__.products_a __import__.order_line_2,"OL B",__import__.products_b

And finally, import the files, and take into account: import Products.csv before OrderLine.csv.

EDIT

I think it should be better to waste a bit of time in programming a macro for your CSV editor (Excel, LibreOffice, Open Office or whatever), but if you're desperated and you need to do this only through Odoo, I came up with an awful workaround, but at least, it should work too.

1.Create a new Char field named product_code in order_line model (it would be there temporaly).

2.Modify the ORM create method of this model:

@api.model
def create(self, vals):
    product_id = False
    product_code = vals.get('product_code', False)
    if product_code:
        product = self.env['products'].search([
            ('product_code', '=', product_code)
        ])
        if product:
            product_id = product[0].id
    vals.update({
        'products': product_id,
    })
    return super(OrderLine, self).create(vals)

3.Copy the file which the customer's sent you, rename the headers properly, and rename the column order/products/product_code as product_code. Import the CSV file. Each importation of records will call the ORM create method of order_line model.

After the importation you'll have in the database the order lines rightly related to the products.

When you've finished you'll have to remember to remove the code you've added (and also remove the column product_code from order_line model in the database, in order to remove junk).

1
votes

Solution 1

You can create a transient model with the fields that you are using in the CSV. And applying the idea of @forvas:

class ImportOrderLines(models.TransientModel):
    _name = 'import.order.lines'

    product_code = Char()

    @api.model
    def create(self, vals):
        product_id = False
        product_code = vals.get('product_code', False)
        if product_code:
            product = self.env['products'].search([
                ('product_code', '=', product_code)
            ])
            if product:
                product_id = product[0].id

        self.env['order_line'].create({
            'products': product_id,
        })
        return False   # you don't need to create the record in the transient model

You can go to the list view of this transient model and import like in any other model, with the base_import view.

Solution 2

You could create a wizard in order to import the CSV to create the Order Lines. Check the following source code. You must assing the method import_order_lines to a button in the wizard.

import base64
import magic
import csv
from cStringIO import StringIO
import codecs

from openerp import models, fields, api, _
from openerp.exceptions import Warning


class ImportDefaultCodeWizard(models.TransientModel):
    _name = 'import.default_code.wizard'

    name = fields.Char(
        string='File name',
    )

    file = fields.Binary(
        string='ZIP file to import to Odoo',
        required=True,
    )

    @api.multi
    def import_order_lines(self):
        self.ensure_one()
        content = base64.decodestring(self.file)

        if codecs.BOM_UTF8 == content[:3]:  # remove "byte order mark" (windows)
            content = content[3:]

        file_type = magic.from_buffer(content, mime=True)

        if file_type == 'text/plain':
            self._generate_order_line_from_csv(content)
            return self._show_result_wizard()

        raise Warning(
            _('WRONG FILETYPE'),
            _('You should send a CSV file')
        )

    def _show_result_wizard(self):
        return {
            'type': 'ir.actions.act_window',
            'res_model': self._name,
            'view_type': 'form',
            'view_mode': 'form',
            'target': 'new',
            'context': self.env.context,
        }        

    def _generate_order_line_from_csv(self, data):
        try:
            reader = csv.DictReader(StringIO(data))
        except Exception:
            raise Warning(
                _('ERROR getting data from csv file'
                '\nThere was some error trying to get the data from the csv file.'
                '\nMake sure you are using the right format.'))
        n = 1

        for row in reader:
            n += 1
            self._validate_data(n, row)

            default_code = row.get('default_code', False)


            order_line = {
                'default_code': self._get_product_id(default_code),

                # here you should add all the order line fields
            }

            try:
                self.env['order_line'].create(order_line)
            except Exception:
                raise Warning(
                    _('The order line could not be created.'
                    '\nROW: %s') % n
                )

    def _validate_data(self, n, row):
        csv_fields = [
            'default_code',
        ]
        """ here is where you should add the CSV fields in order to validate them
                customer/account_number, customer/first_name, customer/last_name, 
                customer/account_type, order/transaction_id, order/products/product_code ,order/quantity, order/customer_id/id
        """


        for key in row:
            if key not in csv_fields:
                raise Warning(_('ERROR\nThe file format is not right.'
                                '\nCheck the column names and the CSV format'
                                '\nKEY: %s' % key))

        if row.get('default_code', False) == '':
            raise Warning(
                _('ERROR Validating data'),
                _('The product code should be filled.'
                '\nROW: %s') % n
            )

    def _get_product_id(self, default_code):
        if partner_id:
            product_obj = self.env['product.product'].search([
                ('default_code', '=', default_code),
            ])
            if len(product_code_obj) == 1:
                return product_obj.default_code
            else:
                raise Warning(
                    _('ERROR Validating data'),
                    _('The product code should be filled.'
                    '\nROW: %s') % n
                )        
            return False
0
votes

You can search by product_code like so:

@api.model
def search_by_code(self, code):
    result = self.env['products'].search([('product_code', '=', code)])