Welcome to BACON:CONSULT‎ > ‎Services‎ > ‎odoo‎ > ‎OpenERP Developments‎ > ‎xwPython‎ > ‎

xwPython and OpenERP

Example of an interactive OpenERP report using xwPython 

This is an example of a stand alone xwPython report application - interfacing to an OpenERP database instance. The approach taken in this example is quite different as xwPython was installed on the client and not on the server and the data is "Pulled" from the openERP server using a remote XML-RPC connection. 

The beauty of using xwPython is that it's possible to create very attractive menu driven application and setup user prompts which is especally useful when creating reports as parameters can be setup as users are prompted for a value or values when they run the report. The ability to provide parameters is an important part of creating a report. 

Code is written into IDLE or other Python IDE using the libraries from xwPython. 



The xwPython code then extracts the data from respective models in the OpenERP database. This exercise is merely a proof of concept.

This example report is a pre-production report, where an operator may needs to collect all BOM components from the warehouse, based on the volume to be produced.  To make this report more effective the quantities could have been retrieved automatically based on the production work-order report, as this report has all the details of volumes and details of the order. 

The application demonstrates pop-up dialog boxes and also dynamic selection dialog boxes. 

The application is run from IDLE. (The xwPython libraries need to be installed first)

Enter production Quantities


This figure is used to then calculate the BOM components. The quantities for each component are extracted from the BOM.


TextEntryDialog Box

# ------------------------------------------------------------------
# Build a pop question box 
 # ------------------------------------------------------------------
box2=wx.TextEntryDialog(None, "Enter Quantity of Product to be produced?", "Quantity to Produce", "1")
        if box2.ShowModal()==wx.ID_OK:
            quantity = box2.GetValue()Pop


Select the BOM to produce


All available BOMs are extracted and listed in a selection dialog box

Text Box

box3=wx.SingleChoiceDialog(None, "What product are you searching for?", "Product ID", alist  )
        if box3.ShowModal()==wx.ID_OK:
            answer = box3.GetStringSelection()


Final Report

This example prints the results to the main canvas. Menus and Slides can be added.





xwPython Code

xwPython Source Code

# -*- coding: cp1252 -*-
import wx
import xmlrpclib






sock = xmlrpclib.ServerProxy('http://add you IP address here:8069/xmlrpc/object') 

#if your OpenERP instant is installed locally then just add http://localhost/xmlrpc/objecthere
 
uid = 1 
pwd = 'admin'
 
dbname ='add your database name here'

text = []
child1 = []

#start the .pdf engine from www.reportlab.com
from reportlab.pdfgen import canvas
def hello(c):
    c.drawString(100,100,"Hello World")
c = canvas.Canvas("hello2.pdf")
hello(c)
c.showPage()
c.save()
 


class BOM_List_Frame(wx.Frame):
   
    def __init__(self, parent, id ):
       # ------------------------------------------------------------------
       # Reset all constants
       # ------------------------------------------------------------------

        y=50
        y2=0
        i=0
        childs=0

        
        wx.Frame.__init__(self, parent, -1,   title='BOM Report', size=(800,1000))
        panel = wx.Panel(self)
        panel.SetBackgroundColour("white")

        
        scroll = wx.ScrolledWindow(panel, -1)
        #scroll.SetScrollbars(1, 1, 600, 400)
        #self.button = wx.Button(self.scroll, -1, "Scroll Me", pos=(50, 20))
        #self.Bind(wx.EVT_BUTTON,  self.OnClickTop, self.button)
        #self.button2 = wx.Button(self.scroll, -1, "Scroll Back", pos=(500, 350))
        #self.Bind(wx.EVT_BUTTON, self.OnClickBottom, self.button2)

        
        status = self.CreateStatusBar()
        menubar = wx.MenuBar()
        first=wx.Menu()
        second=wx.Menu()
        first.Append (wx.NewId(),"Close", "This will close the window"  )
        first.Append (wx.NewId(),"Open...", "This will open the window"  )
        menubar.Append(first, "File")
        menubar.Append(second, "Edit")
        self.SetMenuBar(menubar)
        #box=wx.MessageDialog(None,'Press OK to Continue. \n The form will then be created', 'Continue?', wx.OK)
        #answer=box.ShowModal()
        #box.Destroy()

        # ------------------------------------------------------------------
        # Build a pop question box 
        # ------------------------------------------------------------------
        
        box2=wx.TextEntryDialog(None, "Enter Quantity of Product to be produced?", "Quantity to Produce", "1")
        if box2.ShowModal()==wx.ID_OK:
            quantity = box2.GetValue()
        
        # ------------------------------------------------------------------
        # find all products with a BOM i.e. where bom field != blank
        # ------------------------------------------------------------------
        args = [('bom_lines', '!=', '')]                                            #query clause
        ids = sock.execute(dbname, uid, pwd, 'mrp.bom', 'search', args)             #Query the mrp.bom model
        ids=sorted(ids)                                                             #sort these id's
        # ------------------------------------------------------------------
        # Print all found record ids as a summary
        # ------------------------------------------------------------------
        
        title=wx.StaticText(panel, -1, "Summary BOM List", (200, 0), (100, -1), wx.ALIGN_CENTER)
        title.SetBackgroundColour('blue')
        title.SetForegroundColour('white')

        # ------------------------------------------------------------------
        # Print a summary of all BOM ID's
        # ------------------------------------------------------------------

        
        y=y+20
        ids2=[]
        
        # ------------------------------------------------------------------
        # Build a drop down menu
        # ------------------------------------------------------------------

        #bom_fields = ('name', 'product_id','bom_lines'  )
        bom_fields = ('product_id','name')
        ListOfProducts2 = []
        alist = []
        for i in range(len(ids)):
            bom_id1 = sock.execute(dbname, uid, pwd, ('mrp.bom'), 'read', ids[i], bom_fields)
            bom_name=bom_id1['name'], # this filters out the product name
            alist.extend(bom_name)
            #print bom_name #for debug only
        print alist #for debug only
        box3=wx.SingleChoiceDialog(None, "What product are you searching for?", "Product ID", alist  )
        if box3.ShowModal()==wx.ID_OK:
            answer = box3.GetStringSelection()
            

                
        
        # ------------------------------------------------------------------
        # find the BOMid of the item selected 
        # ------------------------------------------------------------------
        #args = [('bom_lines', '=', answer)]  #query clause
        args = [('name', '=', answer)]  #Search for the record where the selected item name matches. The name needs to be unique
        ids2 = sock.execute(dbname, uid, pwd, 'mrp.bom', 'search', args)     #Query the mrp.bom model
        ids2=sorted(ids2)         
        print "answer = ", (answer), ids2
        ids3 = ids2[0]      #Assume the first record in the list is the only record found. If the name is not unique this causes problems
        ids3 = int(ids3)    #Convert to Integer as the record id to search

        # ------------------------------------------------------------------
        # Get the details of the child for each master bom record
        # Field Product ID returns the product ID and name of the product in tht product.product table
        # Which is useful to retrieve all details of the parent and child BOM too.
        # ------------------------------------------------------------------
        bom_fields = ('name', 'product_id','bom_lines')
        bom_fields2 = ('name', 'product_id','bom_lines','product_qty' )

        # ------------------------------------------------------------------
        # Build up the form with lines between each BOM component
        # ------------------------------------------------------------------

        text2 = '-----------------------------------------------------------------------------'
        self.quote = wx.StaticText(panel, label= text2 + '\n', pos=(20, y))  #Print the line on the screen canvas
        y=y+20 #go the the next line on the screen canvas

        # ------------------------------------------------------------------
        # Read the complete record for the item selected
        # ------------------------------------------------------------------
        bom_id1 = sock.execute(dbname, uid, pwd, ('mrp.bom'), 'read', ids3, bom_fields) 


        # ------------------------------------------------------------------
        # Split the list into indivual fields 
        # ------------------------------------------------------------------
        bom_id = str(bom_id1['id'])
        product_id = str(bom_id1['product_id'])
        bom_lines = str(bom_id1['bom_lines'])



        # ------------------------------------------------------------------
        # Prepare the Form HEADER
        # ------------------------------------------------------------------
       
        self.quote = wx.StaticText(panel, label= 'Master BOM ID = ' + bom_id  + '\n' , pos=(20, y))
        y=y+20  

        self.quote = wx.StaticText(panel, label= 'Product ID= ' + product_id  + '\n' , pos=(20, y))
        y=y+20  

        self.quote = wx.StaticText(panel, label= 'BOM Lines= '+ bom_lines  + '\n' , pos=(20, y))
        y=y+20

        text9 = '_'   # The is used to generate the line between each record     
        self.quote = wx.StaticText(panel, label= text9.ljust(150,'_') +  '\n', pos=(30, y))  #draw a line across the page
        y=y+20

       
        text9 = '_'   # The is used to generate the line between each record     
        self.quote = wx.StaticText(panel, label= '   BOM Child ID    ' + '        Pecentage %      ' +  '         Qty (Kg)         '+ '  Fiche Qty (Kg)      ' +  '        Product_ID          ' +    '           Name           '  + '\n', pos=(30, y))
        y=y+20

        self.quote = wx.StaticText(panel, label= text9.ljust(150,'_') +  '\n', pos=(30, y))  #draw a line across the page
        y=y+20
        
        # ------------------------------------------------------------------
        # get childs boms and show these too
        # ------------------------------------------------------------------
        text4 = [] # Clear the content of the variable
        
        for child1 in bom_id1['bom_lines']:
            bom_child1 = sock.execute(dbname, uid, pwd, ('mrp.bom'), 'read', child1, bom_fields2)
            # Extract the parent BOM ID of this child to see if this also has a BOM    
            anewlist = bom_child1 ['product_id']
            text4= str(child1)
            text4= text4.strip()
            text5= str(anewlist [0])
            text5= text5.strip()
            text6= str(anewlist [1] )
            text6= text6.strip()
            text7= str(bom_child1 ['product_qty'])
            text7= text7.strip()
            text8= (bom_child1['product_qty'])  # Calculate the Fiche Volume - Get the weight in BOM component
            text10= (text8 * 100)               # Calculate the Fiche % - product_qty * 100
            text8= (text8* int(quantity))       # Calculate the Fiche Volume - Qty X weight in BOM component
            text8= str(text8)                   # Calculate the Fiche Volume - Convert to string
            text10= str(text10)                  # Calculate the Fiche % - Convert to string
            
            self.quote = wx.StaticText(panel, label= '|               ' + text4.ljust(5) + '         |           ' +  text10.ljust(5,'0') + '         |          '  + text7.ljust(5,'0') + '        |       '  + text8.ljust(5,'0') + '          |          ' +  text5.ljust(10) + '        |       '  + text6.ljust(10)   + '\n', pos=(30, y))
            y=y+20
            self.quote = wx.StaticText(panel, label= text9.ljust(150,'_') +  '\n', pos=(30, y))
            y=y+20

        
        self.Show()

        def OnClickTop(self, event):
            self.scroll.Scroll(600, 400)
        
        def OnClickBottom(self, event):
            self.scroll.Scroll(1, 1)




if __name__=='__main__':
    app = wx.PySimpleApp()
    frame= BOM_List_Frame (parent=None, id=-1)
    frame.Show()
    app.MainLoop()





ċ
Colin Bacon,
Oct 18, 2012, 1:54 PM
Comments