merge
authorFabien Pinckaers <fp@tinyerp.com>
Tue, 14 Oct 2008 12:37:47 +0000 (14:37 +0200)
committerFabien Pinckaers <fp@tinyerp.com>
Tue, 14 Oct 2008 12:37:47 +0000 (14:37 +0200)
bzr revid: fp@tinyerp.com-20081014123747-ygg1mr3hjm0oleyv

15 files changed:
addons/account/account.py
addons/account_report/report/print_indicator.py
addons/delivery/delivery_view.xml
addons/product/product.py
addons/product/product_view.xml
addons/sale/sale.py
addons/sale/sale_report.xml
bin/addons/base/ir/ir_actions.py
bin/addons/base/ir/ir_ui_view.py
bin/addons/base/ir/wizard/wizard_menu.py
bin/osv/expression.py
bin/report/render/rml2pdf/utils.py
bin/tools/amount_to_text_en.py [new file with mode: 0755]
setup.py
win32/OpenERPServerService.py

index ce5dbf0..7290371 100644 (file)
@@ -844,7 +844,7 @@ class account_move(osv.osv):
 
                 if line.account_id.currency_id:
                     if line.account_id.currency_id.id != line.currency_id.id and (line.account_id.currency_id.id != line.account_id.company_id.currency_id.id or line.currency_id):
-                            raise osv.except_osv(_('Error'), _('Couldn\'t create move with currency different than the secondary currency of the account'))
+                            raise osv.except_osv(_('Error'), _('Couldn\'t create move with currency different than the secondary currency of the account "%s - %s". Clear the secondary currency field of the account definition if you want to accept all currencies.' % (line.account_id.code, line.account_id.name)))
 
             if abs(amount) < 0.0001:
                 if not len(line_draft_ids):
@@ -1851,9 +1851,6 @@ class wizard_multi_charts_accounts(osv.osv_memory):
         obj_journal = self.pool.get('account.journal')
         obj_acc_template = self.pool.get('account.account.template')
 
-        if obj_multi.code_digits<=5:
-            raise osv.except_osv(_('User Error'), _('Account code should be of more than 5 digits.'))
-
         # Creating Account
         obj_acc_root = obj_multi.chart_template_id.account_root_id
         tax_code_root_id = obj_multi.chart_template_id.tax_code_root_id.id
@@ -1936,7 +1933,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
                 'name': (obj_acc_root.id == account_template.id) and obj_multi.company_id.name or account_template.name,
                 #'sign': account_template.sign,
                 'currency_id': account_template.currency_id and account_template.currency_id.id or False,
-                'code': code_acc[:dig],
+                'code': code_acc,
                 'type': account_template.type,
                 'user_type': account_template.user_type and account_template.user_type.id or False,
                 'reconcile': account_template.reconcile,
index 4649443..4b97289 100644 (file)
@@ -35,11 +35,8 @@ from crm.report import report_businessopp
 from report.interface import report_int
 from reportlab.graphics.shapes import Drawing
 from reportlab.graphics.charts.barcharts import VerticalBarChart
-import reportlab.lib.colors as colors
-#from reportlab.graphics.widgetbase import Widget, TypedPropertyCollection
-#from reportlab.graphics.charts.textlabels import BarChartLabel
+import reportlab.lib.colors
 #from reportlab.graphics import renderPM
-import tools
 
 class accounting_report1(report_sxw.rml_parse):
 
@@ -49,88 +46,34 @@ class accounting_report1(report_sxw.rml_parse):
         self.localcontext.update({
             'time': time,
             'test': self.test1,
-            'lines':self.lines,
+#            'childs':self.process
         })
-        self.count=0
-        self.list=[]
 
-    def lines(self,data):
-        res={}
-        result=[]
-        obj_inds=self.pool.get('account.report.report').browse(self.cr,self.uid,data['indicator_id'])
-        def find_child(obj):
-            self.list.append(obj)
-            if obj.child_ids:
-                for child in obj.child_ids:
-                    find_child(child)
-            return True
-        find_child(obj_inds)
-
-        for obj_ind in self.list:
-            res = {
-                'id':obj_ind.id,
-                'name':obj_ind.name,
-                'code':obj_ind.code,
-                'expression':obj_ind.expression,
-                'disp_graph':obj_ind.disp_graph,
-                'note':obj_ind.note,
-                'type':obj_ind.type
-                }
-            result.append(res)
-        return result
-
-    def test1(self,data,object):
-        path=tools.config['root_path']+"/Temp_report/Image"
-        obj_history=self.pool.get('account.report.history')
-
-        if data['select_base']=='year':
-            tuple_search=('fiscalyear_id','in',data['base_selection'][0][2])
-        else:
-            tuple_search=('period_id','in',data['base_selection'][0][2])
-
-        history_ids=obj_history.search(self.cr,self.uid,[('name','=',object['id']),tuple_search])
-        obj_his=obj_history.browse(self.cr,self.uid,history_ids)
-
-        data_val=[]
-        data_period=[]
-        for item in obj_his:
-            data_val.append(item.val)
-            data_period.append(item.period_id.name)
-        self.count +=1
-        drawing = Drawing(400, 300)
+    def test1(self):
+        drawing = Drawing(400, 200)
         data = [
-                 tuple(data_val),
+                 (13, 5, 20, 22, 37, 45, 19, 4),
+                 (11, 3, 10, 22, 30, 25, 29, 6),
                  ]
-        value_min=0.0
-        vmin=min(data_val)
-        vmax=max(data_val)
-
-        val_min=((vmin < 0.00 and vmin-2.00)  or 0.00)
-        # calculating maximum
-        val_max=(vmax/(pow(10,len(str(int(vmax)))-2))+1)*pow(10,len(str(int(vmax)))-2)
         bc = VerticalBarChart()
         bc.x = 50
         bc.y = 50
-        bc.height = 245
+        bc.height = 125
         bc.width = 300
         bc.data = data
-        value_step=(abs(val_max)-abs(val_min))/5
-
-        bc.strokeColor = colors.black
-        bc.valueAxis.valueMin = val_min
-        bc.valueAxis.valueMax = val_max
-        bc.valueAxis.valueStep = value_step
-
+        bc.strokeColor = reportlab.lib.colors.black
+        bc.valueAxis.valueMin = 0
+        bc.valueAxis.valueMax = 50
+        bc.valueAxis.valueStep = 10
         bc.categoryAxis.labels.boxAnchor = 'ne'
         bc.categoryAxis.labels.dx = 8
-
         bc.categoryAxis.labels.dy = -2
         bc.categoryAxis.labels.angle = 30
-        bc.categoryAxis.categoryNames = data_period
+        bc.categoryAxis.categoryNames = ['Jan-99','Feb-99','Mar-99',
+               'Apr-99','May-99','Jun-99','Jul-99','Aug-99']
         drawing.add(bc)
-        drawing.save(formats=['png'],fnRoot=path+str(self.count),title="helo")
-#        renderPM.drawToFile(drawing1, 'example1.jpg','jpg')
-        return path+str(self.count)+'.png'
+#        renderPM.drawToFile(drawing, 'example1.jpg','jpg')
+        return True
 
 
 report_sxw.report_sxw('report.print.indicators', 'account.report.history',
index 07dec15..a29fdde 100644 (file)
@@ -62,7 +62,7 @@
                     <field name="active" select="1"/>
                     <field name="carrier_id" select="1"/>
                     <field name="sequence" select="1"/>
-                    <notebook>
+                    <notebook colspan="4">
                         <page string="Grid definition">
                             <field colspan="4" name="line_ids" nolabel="1" select="1"/>
                         </page>
index b3a9f77..3b1b78b 100644 (file)
@@ -531,6 +531,7 @@ class product_packaging(osv.osv):
     _description = "Packaging"
     _rec_name = 'ean'
     _columns = {
+        'sequence': fields.integer('Sequence'),
         'name' : fields.char('Description', size=64),
         'qty' : fields.float('Quantity by Package',
             help="The total number of products you can put by palet or box."),
@@ -559,6 +560,7 @@ class product_packaging(osv.osv):
 
     _defaults = {
         'rows' : lambda *a : 3,
+        'sequence' : lambda *a : 1,
         'ul' : _get_1st_ul,
     }
 
index ad35962..30b07fe 100644 (file)
                             <field colspan="4" name="packaging" nolabel="1">
                                 <form string="Packaging">
                                     <field name="ean" select="1"/>
+                                    <field name="sequence"/>
                                     <newline/>
                                     <field name="qty" select="1"/>
                                     <field name="ul"/>
             <field name="type">tree</field>
             <field name="arch" type="xml">
                 <tree string="Packaging">
+                    <field name="sequence"/>
                     <field name="ean"/>
                     <field name="qty"/>
                     <field name="ul"/>
             <field name="arch" type="xml">
                 <form string="Packaging">
                     <field name="product_id" select="1"/>
+                    <newline/>
                     <field name="ean" select="1"/>
+                    <field name="sequence"/>
                     <newline/>
                     <field name="qty" select="1"/>
                     <field name="ul"/>
index 3bbc650..5434562 100644 (file)
@@ -451,7 +451,8 @@ class sale_order(osv.osv):
     def test_state(self, cr, uid, ids, mode, *args):
         assert mode in ('finished', 'canceled'), _("invalid mode for test_state")
         finished = True
-        canceled = False
+        canceled = False 
+        notcanceled = False
         write_done_ids = []
         write_cancel_ids = []
         for order in self.browse(cr, uid, ids, context={}):
@@ -460,6 +461,8 @@ class sale_order(osv.osv):
                     finished = False
                 if line.procurement_id and line.procurement_id.state == 'cancel':
                     canceled = True
+                if line.procurement_id and line.procurement_id.state <> 'cancel':
+                    notcanceled = True
                 # if a line is finished (ie its procuremnt is done or it has not procuremernt and it
                 # is not already marked as done, mark it as being so...
                 if ((not line.procurement_id) or line.procurement_id.state == 'done') and line.state != 'done':
@@ -475,6 +478,8 @@ class sale_order(osv.osv):
         if mode=='finished':
             return finished
         elif mode=='canceled':
+            if notcanceled:
+                return False
             return canceled
 
     def action_ship_create(self, cr, uid, ids, *args):
index 8ced0a1..afb43b8 100644 (file)
@@ -23,7 +23,7 @@
                rml="sale/report/prepare_allot.rml"
                auto="False"/>
        -->
-        <report auto="False" id="report_sale_order" model="sale.order" name="sale.order" rml="sale/report/order.rml" string="Print Order"/>
-        
+        <report auto="False" id="report_sale_order" model="sale.order" name="sale.order" rml="sale/report/order.rml" string="Quotation / Order"/>
+
     </data>
 </openerp>
index a0ac5a2..2e3d683 100644 (file)
@@ -231,7 +231,8 @@ class act_window_view(osv.osv):
             ('tree', 'Tree'),
             ('form', 'Form'),
             ('graph', 'Graph'),
-            ('calendar', 'Calendar')), string='Type of view', required=True),
+            ('calendar', 'Calendar'),
+            ('gantt', 'Gantt')), string='Type of view', required=True),
         'act_window_id': fields.many2one('ir.actions.act_window', 'Action', ondelete='cascade'),
         'multi': fields.boolean('On multiple doc.',
             help="If set to true, the action will not be displayed on the right toolbar of a form views."),
index 276568c..e3e7e63 100644 (file)
@@ -66,7 +66,8 @@ class view(osv.osv):
             ('tree','Tree'),
             ('form','Form'),
             ('graph', 'Graph'),
-            ('calendar', 'Calendar')), 'View Type', required=True),
+            ('calendar', 'Calendar'),
+            ('gantt', 'Gantt')), 'View Type', required=True),
         'arch': fields.text('View Architecture', required=True),
         'inherit_id': fields.many2one('ir.ui.view', 'Inherited View', ondelete='cascade'),
         'field_parent': fields.char('Childs Field',size=64),
index 3724b1d..9030a6c 100644 (file)
@@ -77,7 +77,12 @@ class wizard_model_menu_line(osv.osv_memory):
     _columns = {
         'wizard_id': fields.many2one('wizard.ir.model.menu.create','Wizard'),
         'sequence': fields.integer('Sequence'),
-        'view_type': fields.selection([('tree','Tree'),('form','Form'),('graph','Graph'),('calendar','Calendar')],'View Type',required=True),
+        'view_type': fields.selection([
+            ('tree','Tree'),
+            ('form','Form'),
+            ('graph','Graph'),
+            ('calendar','Calendar'),
+            ('gantt','Gantt')],'View Type',required=True),
         'view_id': fields.many2one('ir.ui.view', 'View'),
     }
     _defaults = {
index 1e21443..7397a82 100644 (file)
@@ -232,9 +232,9 @@ class expression(object):
                 query = '(%s OR %s IS NULL)' % (query, left)
         else:
             params = []
-            if right is False and operator == '=':
+            if (right == False or right is None) and operator == '=':
                 query = '%s IS NULL' % left
-            elif right is False and operator in ['<>', '!=']:
+            elif (right == False or right is None) and operator in ['<>', '!=']:
                 query = '%s IS NOT NULL' % left
             else:
                 if left == 'id':
index 35460a2..a3c68d1 100644 (file)
@@ -57,7 +57,7 @@ def text_get(node):
 
 units = [
     (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch),
-    (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),  
+    (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),
     (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm),
     (re.compile('^(-?[0-9\.]+)\s*$'), 1)
 ]
@@ -93,7 +93,7 @@ def attr_get(node, attrs, dict={}):
             elif dict[key]=='int':
                 res[key] = int(node.getAttribute(key))
             elif dict[key]=='unit':
-                res[key] = unit_get(node.getAttribute(name))
+                res[key] = unit_get(node.getAttribute(key))
     return res
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/bin/tools/amount_to_text_en.py b/bin/tools/amount_to_text_en.py
new file mode 100755 (executable)
index 0000000..61d6f5f
--- /dev/null
@@ -0,0 +1,149 @@
+# -*- coding: iso8859-1 -*-
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+#                    Fabien Pinckaers <fp@tiny.Be>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+#-------------------------------------------------------------
+#ENGLISH
+#-------------------------------------------------------------
+
+ones = {
+    0: '', 1:'One', 2:'Two', 3:'Three', 4:'Four', 5:'Five', 6:'Six', 7:'Seven', 8:'Eight', 9:'Nine',
+    10:'Ten', 11:'Eleven', 12:'Twelve', 13:'Thirteen', 14:'Forteen', 15:'Fifteen', 16:'Sixteen', 17:"Seventeen",18:"Eighteen",19:"Nineteen",
+}
+
+tens = {
+    1: 'Ten', 2: 'Twenty ', 3:'Thirty', 4:'Forty', 5:'Fifty', 6: 'Sixty', 7 : 'Seventy', 8:'Eighty' ,9: 'Ninety'}
+
+hundred = {
+     0:'',1: 'One Hundred', 2: 'Two Hundred', 3: 'Three Hundred', 4 :'Four Hundred', 5: 'Five Hundred', 6: 'Six Hundred', 7 :'Seven Hundred', 8:' Eight Hundred ', 9:'Nine Hundred '
+}
+
+thousands ={
+     0:'',1: 'One Thousand'
+}
+
+lacs = {
+     0:'',1: 'Lac'
+}
+
+def _100_to_text(number):
+    if number in ones:
+        return ones[number]
+    else:
+        if number%10>0:
+            return tens[number / 10]+'-'+ones[number % 10]
+        else:
+            return tens[number / 10]
+
+def _1000_to_text(number):
+    d = _100_to_text(number % 100)
+    d2 = number/100
+    if d2>0 and d:
+        return hundred[d2]+' '+d
+    elif d2>1 and not(d):
+        return hundred[d2]+'s'
+    else:
+        return hundred[d2] or d
+
+def _10000_to_text(number):
+    if number==0:
+        return 'zero'
+    part1 = _1000_to_text(number % 1000)
+    part2 = thousands.get(number / 1000,  _1000_to_text(number / 1000)+' Thousands')
+    if part2 and part1:
+        part1 = ' '+part1
+    return part2+part1
+
+def _1000000_to_text(number):
+    if number==0:
+        return 'zero'
+    part1 = _10000_to_text(number % 100000)
+    part2 = lacs.get(number / 100000,  _10000_to_text(number / 100000)+' Lacs')
+    if part2 and part1:
+        part1 = ' '+part1
+    return part2+part1
+
+
+def amount_to_text(number, currency):
+    lacs_number = int(number)
+    units_name = currency
+    if lacs_number > 1:
+        units_name += 's'
+    
+    lacs = _1000000_to_text(lacs_number)
+    lacs = lacs_number and '%s %s' % (lacs, units_name) or ''
+    
+    units_number = int(number * 10000) % 10000
+    units = _10000_to_text(units_number)
+    units = units_number and '%s %s' % (units, units_name) or ''
+    
+    cents_number = int(number * 100) % 100
+    cents_name = (cents_number > 1) and 'cents' or 'cent'
+    cents = _100_to_text(cents_number)
+    cents = cents_number and '%s %s' % (cents, cents_name) or ''
+    return lacs
+
+
+#-------------------------------------------------------------
+# Generic functions
+#-------------------------------------------------------------
+
+_translate_funcs = {'en' : amount_to_text}
+    
+#TODO: we should use the country AND language (ex: septante VS soixante dix)
+#TODO: we should use en by default, but the translation func is yet to be implemented
+def amount_to_text(nbr, lang='en', currency='euro'):
+    """
+    Converts an integer to its textual representation, using the language set in the context if any.
+    Example:
+        1654: thousands six cent cinquante-quatre.
+    """
+    if nbr > 10000000:
+#TODO: use logger    
+        print "WARNING: number too large '%d', can't translate it!" % (nbr,)
+        return str(nbr)
+    
+    if not _translate_funcs.has_key(lang):
+#TODO: use logger    
+        print "WARNING: no translation function found for lang: '%s'" % (lang,)
+#TODO: (default should be en) same as above
+        lang = 'en'
+    return _translate_funcs[lang](nbr, currency)
+
+if __name__=='__main__':
+    from sys import argv
+    
+    lang = 'nl'
+    if len(argv) < 2:
+        for i in range(1,200):
+            print i, ">>", int_to_text(i, lang)
+        for i in range(200,999999,139):
+            print i, ">>", int_to_text(i, lang)
+    else:
+        print int_to_text(int(argv[1]), lang)
+
index 0ae3383..0000ae6 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -155,7 +155,10 @@ f.close()
 options = {"py2exe": {
     "compressed": 0,
     "optimize": 2, 
-    "packages": ["decimal", "xml", "xml.dom", "xml.xpath", "encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing", "pydot"],
+    "packages": ["lxml", "lxml.builder", "lxml._elementpath", "lxml.etree", 
+                 "lxml.objectify", "decimal", "xml", "xml.dom", "xml.xpath", 
+                 "encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing", 
+                 "pydot"],
     "excludes" : ["Tkconstants","Tkinter","tcl"],
     }}
 
index 85cd884..24df255 100644 (file)
@@ -73,15 +73,13 @@ class OpenERPServerService(win32serviceutil.ServiceFramework):
 \r
 \r
     def StartTERP(self):\r
-    # The server finds now its configuration automatically on Windows\r
-    # We start the ERP Server as an independent process, but we keep its handle\r
-    # The server's binary must be one directory above the service's binary (when py2exe'd the python libraries shouldn' mix)\r
-    service_dir = os.path.dirname(sys.argv[0])\r
-    server_dir = os.path.split(service_dir)[0]\r
-    server_path = os.path.join(server_dir, 'openerp-server.exe')\r
-    self.terpprocess = subprocess.Popen([server_path], \\r
-                                            cwd=server_dir,\r
-                        creationflags=win32process.CREATE_NO_WINDOW)\r
+        # The server finds now its configuration automatically on Windows\r
+        # We start the ERP Server as an independent process, but we keep its handle\r
+        # The server's binary must be one directory above the service's binary (when py2exe'd the python libraries shouldn' mix)\r
+        service_dir = os.path.dirname(sys.argv[0])\r
+        server_dir = os.path.split(service_dir)[0]\r
+        server_path = os.path.join(server_dir, 'openerp-server.exe')\r
+        self.terpprocess = subprocess.Popen([server_path], cwd=server_dir, creationflags=win32process.CREATE_NO_WINDOW)\r
 \r
 \r
     def StartControl(self,ws):\r
@@ -93,10 +91,10 @@ class OpenERPServerService(win32serviceutil.ServiceFramework):
     # Start OpenERP Server itself\r
         self.StartTERP()\r
         # start the loop waiting for the Service Manager's stop signal\r
-    thread.start_new_thread(self.StartControl, (self.hWaitStop,))\r
-    # Log a info message that the server is running\r
-    servicemanager.LogInfoMsg("OpenERP Server up and running")\r
-    # verification if the server is really running, else quit with an error\r
+        thread.start_new_thread(self.StartControl, (self.hWaitStop,))\r
+        # Log a info message that the server is running\r
+        servicemanager.LogInfoMsg("OpenERP Server up and running")\r
+        # verification if the server is really running, else quit with an error\r
         self.terpprocess.wait()\r
         if not self.stopping:\r
             sys.exit("OpenERP Server check: server not running, check the logfile for more info")\r