diff --git a/addons/account/account.py b/addons/account/account.py
index 8e5450f808e..64658550ae5 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -159,15 +159,6 @@ class account_account(osv.osv):
return super(account_account,self).search(cr, uid, args, offset, limit,
order, context=context, count=count)
-# def _credit(self, cr, uid, ids, field_name, arg, context={}):
-# return self.__compute(cr, uid, ids, field_name, arg, context, 'COALESCE(SUM(l.credit), 0)')
-#
-# def _debit(self, cr, uid, ids, field_name, arg, context={}):
-# return self.__compute(cr, uid, ids, field_name, arg, context, 'COALESCE(SUM(l.debit), 0)')
-#
-# def _balance(self, cr, uid, ids, field_name, arg, context={}):
-# return self.__compute(cr, uid, ids, field_name, arg, context, 'COALESCE(SUM(l.debit) - SUM(l.credit), 0)')
-
def __compute(self, cr, uid, ids, field_names, arg, context={}, query=''):
mapping = {
'balance': "COALESCE(SUM(l.debit) - SUM(l.credit), 0) as balance ",
@@ -180,7 +171,7 @@ class account_account(osv.osv):
if ids2:
query = self.pool.get('account.move.line')._query_get(cr, uid,
context=context)
- cr.execute(("SELECT l.account_id, " +\
+ cr.execute(("SELECT l.account_id as id, " +\
' , '.join(map(lambda x: mapping[x], field_names)) +
"FROM " \
"account_move_line l " \
@@ -189,19 +180,16 @@ class account_account(osv.osv):
"AND " + query + " " \
"GROUP BY l.account_id") % (acc_set, ))
- for res in cr.fetchall():
- accounts[res[0]] = res[1:]
+ for res in cr.dictfetchall():
+ accounts[res['id']] = res
res = {}
for id in ids:
- res[id] = map(lambda x: 0.0, field_names)
+ res[id] = {}.fromkeys(field_names, 0.0)
ids2 = self.search(cr, uid, [('parent_id', 'child_of', [id])])
for i in ids2:
- for a in range(len(field_names)):
- res[id][a] += accounts.get(i, (0.0,0.0,0.0))[a]
-# TODO: if account.type is consolidation: compute all childs like before +
-# currency conversion
-
+ for a in field_names:
+ res[id][a] += accounts.get(i, {}).get(a, 0.0)
return res
def _get_company_currency(self, cr, uid, ids, field_name, arg, context={}):
@@ -233,6 +221,7 @@ class account_account(osv.osv):
('payable','Payable'),
('view','View'),
('consolidation','Consolidation'),
+ ('other','Others'),
('closed','Closed'),
], 'Internal Type', required=True,),
@@ -474,8 +463,8 @@ class account_fiscalyear(osv.osv):
while ds.strftime('%Y-%m-%d')
-
-
@@ -29,4 +25,4 @@
-
\ No newline at end of file
+
diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py
index d6c4e6aa3ed..e4ad52570b9 100644
--- a/addons/account/account_bank_statement.py
+++ b/addons/account/account_bank_statement.py
@@ -319,7 +319,7 @@ class account_bank_statement(osv.osv):
cursor.execute('SELECT balance_end_real \
FROM account_bank_statement \
WHERE journal_id = %d \
- ORDER BY date DESC LIMIT 1', (journal_id,))
+ ORDER BY date DESC,id DESC LIMIT 1', (journal_id,))
res = cursor.fetchone()
balance_start = res and res[0] or 0.0
diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml
index af057fd36c5..a1f94a9608b 100644
--- a/addons/account/account_view.xml
+++ b/addons/account/account_view.xml
@@ -1411,7 +1411,7 @@
ir.actions.act_window
account.config.fiscalyear
form
- form
+ tree
new
diff --git a/addons/account/data/account_minimal.xml b/addons/account/data/account_minimal.xml
index 5c21ebf9aa2..69d79e3f228 100644
--- a/addons/account/data/account_minimal.xml
+++ b/addons/account/data/account_minimal.xml
@@ -49,7 +49,7 @@ your own chart of account.
Petty Cash
x 570000
- cash
+ other
@@ -64,7 +64,7 @@ your own chart of account.
Products Purchase
x 600000
- expense
+ other
@@ -78,7 +78,7 @@ your own chart of account.
Products Sales
x 701000
- income
+ other
diff --git a/addons/account/partner.py b/addons/account/partner.py
index db1179c7a54..ef68a12de48 100644
--- a/addons/account/partner.py
+++ b/addons/account/partner.py
@@ -55,13 +55,12 @@ class res_partner(osv.osv):
'credit': 'receivable',
'debit': 'payable'
}
- maps = {}
- for i in range(len(field_names)):
- maps[{'credit': 'receivable', 'debit': 'payable' }[field_names[i]]] = i
- res = {}.fromkeys(ids, map(lambda x: 0.0, field_names))
+ maps = {'receivable':'credit', 'payable':'debit' }
+ res = {}
+ for id in ids:
+ res[id] = {}.fromkeys(field_names, 0)
for pid,type,val in cr.fetchall():
- if type in maps:
- res[pid][maps[type]] = val
+ res[pid][maps[type]] = val
return res
def _credit_search(self, cr, uid, obj, name, args):
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
index c513ee0c1ba..344d6c47bf7 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
@@ -667,11 +667,16 @@ class hr_timesheet_sheet_sheet_account(osv.osv):
hr_timesheet_sheet_sheet_account()
+
class res_company(osv.osv):
_inherit = 'res.company'
_columns = {
- 'timesheet_range': fields.selection([('day','Day'),('week','Week'),('month','Month'),('year','Year')], 'Timeshet range'),
- 'timesheet_max_difference': fields.float('Timesheet allowed difference', help="Allowed difference between the sign in/out and the timesheet computation for one sheet. Set this to 0 if you do not want any control."),
+ 'timesheet_range': fields.selection(
+ [('day','Day'),('week','Week'),('month','Month'),('year','Year')], 'Timeshet range',
+ required=True),
+ 'timesheet_max_difference': fields.float('Timesheet allowed difference',
+ help="Allowed difference between the sign in/out and the timesheet " \
+ "computation for one sheet. Set this to 0 if you do not want any control."),
}
_defaults = {
'timesheet_range': lambda *args: 'month',
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
index d3d23e6fb92..5e9c83a4b6c 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
@@ -150,16 +150,16 @@
+
+
+
+
+
+
+
+
+
+ -->
@@ -238,8 +238,8 @@
+ Company inheritancy
+ -->
res.company.sheet
@@ -247,18 +247,18 @@
form
-
-
+
+
-
+
+ hr.analytic.timesheet inheritancy
+ -->
hr.analytic.timesheet.form
@@ -271,10 +271,9 @@
-
+ hr.attendance inheritancy
+ -->
hr.attendance.form
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index 219253c8ccf..e9877ce1349 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -1124,11 +1124,11 @@ class StockPicking(osv.osv):
#
# Explode picking by replacing phantom BoMs
#
- def action_explode(self, cr, uid, ids, *args):
- for pick in self.browse(cr, uid, ids):
+ def action_explode(self, cr, uid, picks, *args):
+ for pick in picks:
for move in pick.move_lines:
self.pool.get('stock.move')._action_explode(cr, uid, move)
- return True
+ return picks
StockPicking()
diff --git a/addons/product/product.py b/addons/product/product.py
index 2d74c3a7139..a48e3932570 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -260,8 +260,8 @@ class product_template(osv.osv):
'warranty': fields.float('Warranty (months)'),
'sale_ok': fields.boolean('Can be sold', help="Determine if the product can be visible in the list of product within a selection from a sale order line."),
'purchase_ok': fields.boolean('Can be Purchased', help="Determine if the product is visible in the list of products within a selection from a purchase order line."),
- 'uom_id': fields.many2one('product.uom', 'Default UOM', required=True),
- 'uom_po_id': fields.many2one('product.uom', 'Purchase UOM', required=True),
+ 'uom_id': fields.many2one('product.uom', 'Default UoM', required=True, help="This is the default Unit of Measure used for all stock operation."),
+ 'uom_po_id': fields.many2one('product.uom', 'Purchase UoM', required=True),
'state': fields.selection([('',''),('draft', 'In Development'),('sellable','In Production'),('end','End of Lifecycle'),('obsolete','Obsolete')], 'Status', help="Tells the user if he can use the product or not."),
'uos_id' : fields.many2one('product.uom', 'Unit of Sale',
help='Keep empty to use the default UOM'),
@@ -347,10 +347,7 @@ class product_product(osv.osv):
def _get_product_available_func(states, what):
def _product_available(self, cr, uid, ids, name, arg, context={}):
- res={}
- for id in ids:
- res.setdefault(id, 0.0)
- return res
+ return {}.fromkeys(ids, 0.0)
return _product_available
_product_qty_available = _get_product_available_func(('done',), ('in', 'out'))
diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml
index 4ce0bf91608..c941bb0f34c 100644
--- a/addons/product/product_view.xml
+++ b/addons/product/product_view.xml
@@ -170,7 +170,7 @@
product.category.list
product.category
tree
- 1
+ 1
diff --git a/addons/project/__init__.py b/addons/project/__init__.py
index 0f75cd3dd76..4290a3ffef6 100644
--- a/addons/project/__init__.py
+++ b/addons/project/__init__.py
@@ -26,7 +26,9 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
###############################################################################
+
import project
+import company
import report
import wizard
diff --git a/addons/project/company.py b/addons/project/company.py
new file mode 100644
index 00000000000..990586c48ee
--- /dev/null
+++ b/addons/project/company.py
@@ -0,0 +1,50 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved.
+#
+# $Id$
+#
+# 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.
+#
+##############################################################################
+
+from osv import fields
+from osv import osv
+
+class res_company(osv.osv):
+ _inherit = 'res.company'
+ _columns = {
+ 'project_time_mode': fields.selection(
+ [('hours','Hours'),('day','Days'),('week','Weeks'),('month','Months')],
+ 'Project Time Unit',
+ help='This will set the unit of measure used in projects and tasks.\n' \
+"If you use the timesheet linked to projects (project_timesheet module), don't " \
+"forget to setup the right unit of measure in your employees.",
+ required=True,
+ ),
+ }
+ _defaults = {
+ 'project_time_mode': lambda *args: 'hours',
+ }
+res_company()
+
diff --git a/addons/project/project.py b/addons/project/project.py
index 65e827685df..3b3211f56c1 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -28,13 +28,12 @@
#
##############################################################################
+from lxml import etree
from mx import DateTime
from mx.DateTime import now
import time
-import netsvc
from osv import fields, osv
-import ir
class project(osv.osv):
_name = "project.project"
@@ -65,7 +64,7 @@ class project(osv.osv):
ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
res_sum = {}
if ids2:
- cr.execute('SELECT project_id, COALESCE(SUM(planned_hours),0) \
+ cr.execute('SELECT project_id, COALESCE(SUM(total_hours),0) \
FROM project_task \
WHERE project_id IN (' + ','.join([str(x) for x in ids2]) + ') \
AND active \
@@ -97,7 +96,7 @@ class project(osv.osv):
if not ids:
return res
cr.execute('''SELECT
- project_id, sum(progress*planned_hours), sum(planned_hours)
+ project_id, sum(progress*total_hours), sum(total_hours)
FROM
project_task
WHERE
@@ -132,7 +131,7 @@ class project(osv.osv):
'warn_header': fields.text('Mail header'),
'warn_footer': fields.text('Mail footer'),
'notes': fields.text('Notes'),
- 'timesheet_id': fields.many2one('hr.timesheet.group', 'Working hours'),
+ 'timesheet_id': fields.many2one('hr.timesheet.group', 'Working Time'),
'state': fields.selection([('open', 'Open'),('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'Status', required=True),
}
@@ -203,16 +202,30 @@ class task(osv.osv):
t3 += map(lambda x: (x,t2[1]+1), t2[0].child_ids)
return result
- def _hours_effect(self, cr, uid, ids, name, args, context):
+# Compute: effective_hours, total_hours, progress
+ def _hours_get(self, cr, uid, ids, field_names, args, context):
task_set = ','.join(map(str, ids))
cr.execute(("SELECT task_id, COALESCE(SUM(hours),0) FROM project_task_work WHERE task_id in (%s) GROUP BY task_id") % (task_set,))
+ hours = dict(cr.fetchall())
res = {}
- for id in ids:
- res[id] = 0.0
- for task_id, sum in cr.fetchall():
- res[task_id] = sum
+ for task in self.browse(cr, uid, ids, context=context):
+ res[task.id] = {}
+ res[task.id]['effective_hours'] = hours.get(task.id, 0.0)
+ res[task.id]['total_hours'] = task.remaining_hours + hours.get(task.id, 0.0)
+ if (task.remaining_hours + hours.get(task.id, 0.0)):
+ res[task.id]['progress'] = min(100.0 * hours.get(task.id, 0.0) / res[task.id]['total_hours'], 100)
+ else:
+ res[task.id]['progress'] = 0.0
+ res[task.id]['delay_hours'] = res[task.id]['total_hours'] - task.planned_hours
return res
+ def onchange_planned(self, cr, uid, ids, planned, effective):
+ return {'value':{'remaining_hours': planned-effective}}
+
+ #_sql_constraints = [
+ # ('remaining_hours', 'CHECK (remaining_hours>=0)', 'Please increase and review remaining hours ! It can not be smaller than 0.'),
+ #]
+
_columns = {
'active': fields.boolean('Active'),
'name': fields.char('Task summary', size=128, required=True),
@@ -220,7 +233,7 @@ class task(osv.osv):
'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'), ('0','Very urgent')], 'Importance'),
'sequence': fields.integer('Sequence'),
'type': fields.many2one('project.task.type', 'Type'),
- 'state': fields.selection([('draft', 'Draft'),('open', 'Open'),('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'Status'),
+ 'state': fields.selection([('draft', 'Draft'),('open', 'Open'),('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'Status', readonly=True, required=True),
'date_start': fields.datetime('Date'),
'date_deadline': fields.datetime('Deadline'),
'date_close': fields.datetime('Date Closed', readonly=True),
@@ -230,16 +243,21 @@ class task(osv.osv):
'history': fields.function(_history_get, method=True, string="Task Details", type="text"),
'notes': fields.text('Notes'),
'start_sequence': fields.boolean('Wait for previous sequences'),
- 'planned_hours': fields.float('Plan. hours'),
- 'effective_hours': fields.function(_hours_effect, method=True, string='Eff. Hours'),
- 'progress': fields.integer('Progress (0-100)'),
+
+ 'planned_hours': fields.float('Planned Hours', readonly=True, states={'draft':[('readonly',False)]}),
+ 'effective_hours': fields.function(_hours_get, method=True, string='Hours Spent', multi='hours', store=True),
+ 'remaining_hours': fields.float('Remaining Hours', digits=(16,2)),
+ 'total_hours': fields.function(_hours_get, method=True, string='Total Hours', multi='hours', store=True),
+ 'progress': fields.function(_hours_get, method=True, string='Progress (%)', multi='hours', store=True),
+ 'delay_hours': fields.function(_hours_get, method=True, string='Delay Hours', multi='hours', store=True),
+
'user_id': fields.many2one('res.users', 'Assigned to'),
'partner_id': fields.many2one('res.partner', 'Partner'),
- 'work_ids': fields.one2many('project.task.work', 'task_id', 'Work done'),
+ 'work_ids': fields.one2many('project.task.work', 'task_id', 'Work done', readonly=False, states={'draft':[('readonly',True)]}),
}
_defaults = {
'user_id': lambda obj,cr,uid,context: uid,
- 'state': lambda *a: 'open',
+ 'state': lambda *a: 'draft',
'priority': lambda *a: '2',
'progress': lambda *a: 0,
'sequence': lambda *a: 10,
@@ -249,6 +267,31 @@ class task(osv.osv):
}
_order = "state, sequence, priority, date_deadline, id"
+ #
+ # Override view according to the company definition
+ #
+ def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False):
+ tm = self.pool.get('res.users').browse(cr, uid, uid, context).company_id.project_time_mode
+ f = self.pool.get('res.company').fields_get(cr, uid, ['project_time_mode'], context)
+ word = dict(f['project_time_mode']['selection'])[tm]
+
+ res = super(task, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar)
+ if tm=='hours':
+ return res
+ eview = etree.fromstring(res['arch'])
+ def _check_rec(eview, tm):
+ if eview.attrib.get('widget',False) == 'float_time':
+ eview.set('widget','float')
+ for child in eview:
+ _check_rec(child, tm)
+ return True
+ _check_rec(eview, tm)
+ res['arch'] = etree.tostring(eview)
+ for f in res['fields']:
+ if 'Hours' in res['fields'][f]['string']:
+ res['fields'][f]['string'] = res['fields'][f]['string'].replace('Hours',word)
+ return res
+
def do_close(self, cr, uid, ids, *args):
request = self.pool.get('res.request')
tasks = self.browse(cr, uid, ids)
@@ -265,7 +308,7 @@ class task(osv.osv):
'ref_doc1': 'project.task,%d'% (task.id,),
'ref_doc2': 'project.project,%d'% (project.id,),
})
- self.write(cr, uid, [task.id], {'state': 'done', 'date_close':time.strftime('%Y-%m-%d %H:%M:%S'), 'progress': 100})
+ self.write(cr, uid, [task.id], {'state': 'done', 'date_close':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
if task.parent_id and task.parent_id.state in ('pending','draft'):
self.do_reopen(cr, uid, [task.parent_id.id])
return True
@@ -304,7 +347,7 @@ class task(osv.osv):
'ref_doc1': 'project.task,%d' % task.id,
'ref_doc2': 'project.project,%d' % project.id,
})
- self.write(cr, uid, [task.id], {'state': 'cancelled', 'progress':100})
+ self.write(cr, uid, [task.id], {'state': 'cancelled', 'remaining_hours':0.0})
return True
def do_open(self, cr, uid, ids, *args):
@@ -331,7 +374,7 @@ class project_work(osv.osv):
_columns = {
'name': fields.char('Work summary', size=128),
'date': fields.datetime('Date'),
- 'task_id': fields.many2one('project.task', 'Task', ondelete='cascade'),
+ 'task_id': fields.many2one('project.task', 'Task', ondelete='cascade', required=True),
'hours': fields.float('Hours spent'),
'user_id': fields.many2one('res.users', 'Done by', required=True),
}
@@ -340,6 +383,20 @@ class project_work(osv.osv):
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S')
}
_order = "date desc"
+ def create(self, cr, uid, vals, *args, **kwargs):
+ if 'task_id' in vals:
+ cr.execute('update project_task set remaining_hours=remaining_hours+%.2f where id=%d', (-vals.get('hours',0.0), vals['task_id']))
+ return super(project_work,self).create(cr, uid, vals, *args, **kwargs)
+
+ def write(self, cr, uid, ids,vals,context={}):
+ for work in self.browse(cr, uid, ids, context):
+ cr.execute('update project_task set remaining_hours=remaining_hours+%.2f+(%.2f) where id=%d', (-vals.get('hours',0.0), work.hours, work.task_id.id))
+ return super(project_work,self).write(cr, uid, ids, vals, context)
+
+ def unlink(self, cr, uid, ids, *args, **kwargs):
+ for work in self.browse(cr, uid, ids):
+ cr.execute('update project_task set remaining_hours=remaining_hours+%.2f where id=%d', (work.hours, work.task_id.id))
+ return super(project_work,self).unlink(cr, uid, ids,*args, **kwargs)
project_work()
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index 4bcc2efe358..9f59af14e04 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -26,12 +26,12 @@
-
-
+
+
@@ -209,18 +209,25 @@
@@ -444,6 +456,20 @@
view_mode="tree,form,calendar"
view_type="form"/>
+
+ res.company.task.config
+ res.company
+ form
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/project/project_wizard.xml b/addons/project/project_wizard.xml
index 87a83df6bb6..fa0fc6bf37a 100644
--- a/addons/project/project_wizard.xml
+++ b/addons/project/project_wizard.xml
@@ -1,8 +1,7 @@
-
-
\ No newline at end of file
+
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index df8a41e9748..6490d99f680 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -620,13 +620,6 @@ class sale_order_line(osv.osv):
res[line.id] = 1
return res
- def _get_1st_packaging(self, cr, uid, context={}):
- cr.execute('select id from product_packaging order by id asc limit 1')
- res = cr.fetchone()
- if not res:
- return False
- return res[0]
-
_name = 'sale.order.line'
_description = 'Sale Order line'
_columns = {
@@ -667,7 +660,7 @@ class sale_order_line(osv.osv):
'invoiced': lambda *a: 0,
'state': lambda *a: 'draft',
'type': lambda *a: 'make_to_stock',
- 'product_packaging': _get_1st_packaging,
+ 'product_packaging': lambda *a: False
}
def invoice_line_create(self, cr, uid, ids, context={}):
def _get_line_qty(line):
@@ -766,7 +759,7 @@ class sale_order_line(osv.osv):
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False,
- lang=False, update_tax=True, date_order=False):
+ lang=False, update_tax=True, date_order=False, packaging=False):
product_uom_obj = self.pool.get('product.uom')
partner_obj = self.pool.get('res.partner')
product_obj = self.pool.get('product.product')
@@ -776,7 +769,7 @@ class sale_order_line(osv.osv):
context = {'lang': lang, 'partner_id': partner_id}
if not product:
- return {'value': {'th_weight' : 0,
+ return {'value': {'th_weight' : 0, 'product_packaging': False,
'product_uos_qty': qty}, 'domain': {'product_uom': [],
'product_uos': []}}
@@ -787,6 +780,16 @@ class sale_order_line(osv.osv):
if not date_order:
date_order = time.strftime('%Y-%m-%d')
+
+ result = {}
+ product_obj = product_obj.browse(cr, uid, product, context=context)
+ if packaging:
+ default_uom = product_obj.uom_id and product_obj.uom_id.id
+ pack = self.pool.get('product.packaging').browse(cr, uid, packaging, context)
+ q = product_uom_obj._compute_qty(cr, uid, uom, pack.qty, default_uom)
+ qty = qty - qty % q + q
+ result['product_uom_qty'] = qty
+
price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist],
product, qty or 1.0, partner_id, {
'uom': uom,
@@ -797,35 +800,34 @@ class sale_order_line(osv.osv):
_("Couldn't find a pricelist line matching this product and quantity.\n"
"You have to change either the product, the quantity or the pricelist."))
- product = product_obj.browse(cr, uid, product, context=context)
if uom:
uom2 = product_uom_obj.browse(cr, uid, uom)
- if product.uom_id.category_id.id <> uom2.category_id.id:
+ if product_obj.uom_id.category_id.id <> uom2.category_id.id:
uom = False
if uos:
- if product.uos_id:
+ if product_obj.uos_id:
uos2 = product_uom_obj.browse(cr, uid, uos)
- if product.uos_id.category_id.id <> uos2.category_id.id:
+ if product_obj.uos_id.category_id.id <> uos2.category_id.id:
uos = False
else:
uos = False
- result = {'price_unit': price, 'type': product.procure_method}
- if product.description_sale:
- result['notes'] = product.description_sale
+ result .update({'price_unit': price, 'type': product_obj.procure_method})
+ if product_obj.description_sale:
+ result['notes'] = product_obj.description_sale
if update_tax: #The quantity only have changed
- result['delay'] = (product.sale_delay or 0.0)
+ result['delay'] = (product_obj.sale_delay or 0.0)
taxes = self.pool.get('account.tax').browse(cr, uid,
- [x.id for x in product.taxes_id])
+ [x.id for x in product_obj.taxes_id])
taxep = None
if partner_id:
taxep = self.pool.get('res.partner').browse(cr, uid,
partner_id).property_account_tax
if not taxep or not taxep.id:
- result['tax_id'] = [x.id for x in product.taxes_id]
+ result['tax_id'] = [x.id for x in product_obj.taxes_id]
else:
res5 = [taxep.id]
for t in taxes:
@@ -833,38 +835,39 @@ class sale_order_line(osv.osv):
res5.append(t.id)
result['tax_id'] = res5
- result['name'] = product.partner_ref
+ result['name'] = product_obj.partner_ref
domain = {}
if not uom and not uos:
- result['product_uom'] = product.uom_id.id
- if product.uos_id:
- result['product_uos'] = product.uos_id.id
- result['product_uos_qty'] = qty * product.uos_coeff
- uos_category_id = product.uos_id.category_id.id
+ result['product_uom'] = product_obj.uom_id.id
+ if product_obj.uos_id:
+ result['product_uos'] = product_obj.uos_id.id
+ result['product_uos_qty'] = qty * product_obj.uos_coeff
+ uos_category_id = product_obj.uos_id.category_id.id
else:
result['product_uos'] = False
result['product_uos_qty'] = qty
uos_category_id = False
- result['th_weight'] = qty * product.weight
+ result['th_weight'] = qty * product_obj.weight
domain = {'product_uom':
- [('category_id', '=', product.uom_id.category_id.id)],
+ [('category_id', '=', product_obj.uom_id.category_id.id)],
'product_uos':
[('category_id', '=', uos_category_id)]}
elif uom: # whether uos is set or not
- default_uom = product.uom_id and product.uom_id.id
+ default_uom = product_obj.uom_id and product_obj.uom_id.id
q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom)
- if product.uos_id:
- result['product_uos'] = product.uos_id.id
- result['product_uos_qty'] = q * product.uos_coeff
+ if product_obj.uos_id:
+ result['product_uos'] = product_obj.uos_id.id
+ result['product_uos_qty'] = q * product_obj.uos_coeff
else:
result['product_uos'] = False
result['product_uos_qty'] = q
- result['th_weight'] = q * product.weight
+ result['th_weight'] = q * product_obj.weight
elif uos: # only happens if uom is False
- result['product_uom'] = product.uom_id and product.uom_id.id
- result['product_uom_qty'] = qty_uos / product.uos_coeff
- result['th_weight'] = result['product_uom_qty'] * product.weight
+ result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id
+ result['product_uom_qty'] = qty_uos / product_obj.uos_coeff
+ result['th_weight'] = result['product_uom_qty'] * product_obj.weight
+ # Round the quantity up
return {'value': result, 'domain': domain}
def product_uom_change(self, cursor, user, ids, pricelist, product, qty=0,
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index e1d8012733a..50cf8dbfc0c 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -91,9 +91,24 @@
-
-
-
+
+
+
+
@@ -112,7 +127,6 @@
-
@@ -209,7 +223,7 @@
- New Sale Order / Quotation
+ New Quotation
ir.actions.act_window
sale.order
form
diff --git a/addons/sale/security/ir.model.access.csv b/addons/sale/security/ir.model.access.csv
index c1448a884bc..04064fa910d 100644
--- a/addons/sale/security/ir.model.access.csv
+++ b/addons/sale/security/ir.model.access.csv
@@ -1,5 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_sale_shop,sale.shop,model_sale_shop,sale.group_sale_user,1,0,0,0
-access_sale_order,sale.order,model_sale_order,sale.group_sale_user,1,1,1,1
-access_sale_order_line,sale.order.line,model_sale_order_line,sale.group_sale_user,1,1,1,1
+access_sale_shop,sale.shop,model_sale_shop,group_sale_user,1,0,0,0
+access_sale_order,sale.order,model_sale_order,group_sale_user,1,1,1,1
+access_sale_order_line,sale.order.line,model_sale_order_line,group_sale_user,1,1,1,1
access_sale_shop_admin,sale.shop,model_sale_shop,base.group_system,1,1,1,1
diff --git a/addons/stock/product.py b/addons/stock/product.py
index 5834a187c22..5e0f4b5ee4a 100644
--- a/addons/stock/product.py
+++ b/addons/stock/product.py
@@ -30,6 +30,60 @@
from osv import fields, osv
+class product_product(osv.osv):
+ _inherit = "product.product"
+# def view_header_get(self, cr, user, view_id, view_type, context):
+# print self, cr, user
+# res = super(product_product, self).view_header_get(cr, user, view_id, view_type, context)
+# if res: return res
+# if (not context.get('location', False)):
+# return False
+# cr.execute('select name from stock_location where id=%d', (context['location'],))
+# j = cr.fetchone()[0]
+# if j:
+# return 'Products: '+j
+# return False
+#
+ def _get_product_available_func(states, what):
+ def _product_available(self, cr, uid, ids, name, arg, context={}):
+ if context.get('shop', False):
+ cr.execute('select warehouse_id from sale_shop where id=%d', (int(context['shop']),))
+ res2 = cr.fetchone()
+ if res2:
+ context['warehouse'] = res2[0]
+
+ if context.get('warehouse', False):
+ cr.execute('select lot_stock_id from stock_warehouse where id=%d', (int(context['warehouse']),))
+ res2 = cr.fetchone()
+ if res2:
+ context['location'] = res2[0]
+
+ if context.get('location', False):
+ location_ids = [context['location']]
+ else:
+ cr.execute("select lot_stock_id from stock_warehouse")
+ location_ids = [id for (id,) in cr.fetchall()]
+
+ # build the list of ids of children of the location given by id
+ location_ids = self.pool.get('stock.location').search(cr, uid, [('location_id', 'child_of', location_ids)])
+ res = self.pool.get('stock.location')._product_get_multi_location(cr, uid, location_ids, ids, context, states, what)
+ for id in ids:
+ res.setdefault(id, 0.0)
+ return res
+ return _product_available
+
+ _product_qty_available = _get_product_available_func(('done',), ('in', 'out'))
+ _product_virtual_available = _get_product_available_func(('confirmed','waiting','assigned','done'), ('in', 'out'))
+ _product_outgoing_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('out',))
+ _product_incoming_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('in',))
+ _columns = {
+ 'qty_available': fields.function(_product_qty_available, method=True, type='float', string='Real Stock'),
+ 'virtual_available': fields.function(_product_virtual_available, method=True, type='float', string='Virtual Stock'),
+ 'incoming_qty': fields.function(_product_incoming_qty, method=True, type='float', string='Incoming'),
+ 'outgoing_qty': fields.function(_product_outgoing_qty, method=True, type='float', string='Outgoing'),
+ }
+product_product()
+
class product_product(osv.osv):
_name = 'product.template'
diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml
index 53405b9b51d..ab397a47a87 100644
--- a/addons/stock/product_view.xml
+++ b/addons/stock/product_view.xml
@@ -45,6 +45,7 @@
product.product
form
+ 26
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index e2d060b894c..14e8b4bdd23 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -53,21 +53,6 @@ class stock_incoterms(osv.osv):
}
stock_incoterms()
-#class stock_lot(osv.osv):
-# _name = "stock.lot"
-# _description = "Lot"
-# _columns = {
-# 'name': fields.char('Lot Name', size=64, required=True),
-# 'active': fields.boolean('Active'),
-# 'tracking': fields.char('Tracking', size=64),
-# 'move_ids': fields.one2many('stock.move', 'lot_id', 'Move lines'),
-# }
-# _defaults = {
-# 'active': lambda *a: True,
-# }
-#stock_lot()
-
-
#----------------------------------------------------------
# Stock Location
#----------------------------------------------------------
@@ -87,21 +72,30 @@ class stock_location(osv.osv):
'chained_location_id': fields.many2one('stock.location', 'Chained Location If Fixed'),
'chained_location_type': fields.selection([('','None'),('customer', 'Customer'),('fixed','Fixed Location')], 'Chained Location Type'),
- 'chained_auto_packing': fields.boolean('Chained Auto-Packing'),
+ 'chained_auto_packing': fields.selection(
+ [('auto','Automatic Move'), ('manual','Manual Operation'),('transparent','Automatic No Step Added')],
+ 'Automatic Move',
+ required=True, select=1,
+ help="This is used only if you selected a chained location type.\n" \
+ "The 'Automatic Move' value will create a stock move after the current one that will be "\
+ "validated automatically. With 'Manual Operation', the stock move has to be validated "\
+ "by a worker. With 'Automatic No Step Added', the location is replaced in the original move."
+ ),
'chained_delay': fields.integer('Chained Delay (days)'),
'address_id': fields.many2one('res.partner.address', 'Location Address'),
'comment': fields.text('Additional Information'),
- 'posx': fields.integer('Corridor (X)', required=True),
- 'posy': fields.integer('Shelves (Y)', required=True),
- 'posz': fields.integer('Height (Z)', required=True),
+ 'posx': fields.integer('Corridor (X)'),
+ 'posy': fields.integer('Shelves (Y)'),
+ 'posz': fields.integer('Height (Z)'),
}
_defaults = {
'active': lambda *a: 1,
'usage': lambda *a: 'internal',
'allocation_method': lambda *a: 'fifo',
'chained_location_type': lambda *a: '',
+ 'chained_auto_packing': lambda *a: 'manual',
'posx': lambda *a: 0,
'posy': lambda *a: 0,
'posz': lambda *a: 0,
@@ -110,12 +104,14 @@ class stock_location(osv.osv):
def chained_location_get(self, cr, uid, location, partner=None, product=None, context={}):
result = None
if location.chained_location_type=='customer':
- result = partner.property_stock_customer
+ if partner:
+ result = partner.property_stock_customer
elif location.chained_location_type=='fixed':
result = location.chained_location_id
+ if result:
+ return result, location.chained_auto_packing, location.chained_delay
return result
-
def picking_type_get(self, cr, uid, from_location, to_location, context={}):
result = 'internal'
if (from_location.usage=='internal') and (to_location and to_location.usage in ('customer','supplier')):
@@ -175,9 +171,7 @@ class stock_location(osv.osv):
states_str = ','.join(map(lambda s: "'%s'" % s, states))
if not product_ids:
product_ids = product_obj.search(cr, uid, [])
- res = {}
- for id in product_ids:
- res[id] = 0.0
+ res = {}.fromkeys(product_ids, 0.0)
if not ids:
return res
@@ -332,15 +326,14 @@ class stock_picking(osv.osv):
_name = "stock.picking"
_description = "Packing list"
_columns = {
- 'name': fields.char('Packing name', size=64, required=True, select=True),
+ 'name': fields.char('Reference', size=64, required=True, select=True),
'origin': fields.char('Origin', size=64),
'type': fields.selection([('out','Sending Goods'),('in','Getting Goods'),('internal','Internal'),('delivery','Delivery')], 'Shipping Type', required=True, select=True),
'active': fields.boolean('Active'),
'note': fields.text('Notes'),
- 'location_id': fields.many2one('stock.location', 'Location'),
- 'location_dest_id': fields.many2one('stock.location', 'Dest. Location'),
-
+ #'location_id': fields.many2one('stock.location', 'Location'),
+ #'location_dest_id': fields.many2one('stock.location', 'Dest. Location'),
'move_type': fields.selection([('direct','Direct Delivery'),('one','All at once')],'Delivery Method', required=True),
'state': fields.selection([
('draft','Draft'),
@@ -351,9 +344,7 @@ class stock_picking(osv.osv):
('cancel','Cancel'),
], 'Status', readonly=True, select=True),
'date':fields.datetime('Date Create'),
-
'move_lines': fields.one2many('stock.move', 'picking_id', 'Move Lines'),
-
'auto_picking': fields.boolean('Auto-Packing'),
'address_id': fields.many2one('res.partner.address', 'Partner'),
'invoice_state':fields.selection([
@@ -363,7 +354,7 @@ class stock_picking(osv.osv):
select=True),
}
_defaults = {
- 'name': lambda *a: '/',
+ 'name': lambda self,cr,uid,context: self.pool.get('ir.sequence').get(cr, uid, 'stock.picking'),
'active': lambda *a: 1,
'state': lambda *a: 'draft',
'move_type': lambda *a: 'direct',
@@ -371,64 +362,28 @@ class stock_picking(osv.osv):
'invoice_state': lambda *a: 'none',
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
}
+ def copy(self, cr, uid, id, data=None, context={}):
+ data = data or {}
+ data['name'] = '/'
+ return super(stock_picking, self).copy(cr, uid, id, data, context)
+
def onchange_partner_in(self, cr, uid, context, partner_id=None):
sid = self.pool.get('res.partner.address').browse(cr, uid, partner_id, context).partner_id.property_stock_supplier.id
- return {
- 'value': {'location_id':sid}
- }
+ return { }
- def action_explode(self, cr, uid, ids, *args):
- return True
+ def action_explode(self, cr, uid, moves, context={}):
+ return moves
- def action_confirm(self, cr, uid, ids, *args):
+ def action_confirm(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state': 'confirmed'})
todo = []
for picking in self.browse(cr, uid, ids):
- if picking.name == self._defaults['name']():
- number = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.%s' % picking.type)
- self.write(cr, uid, [picking.id], {'name': number})
for r in picking.move_lines:
if r.state=='draft':
- todo.append(r.id)
+ todo.append(r)
+ todo = self.action_explode(cr, uid, todo, context)
if len(todo):
- self.pool.get('stock.move').action_confirm(cr,uid, todo)
- self.action_explode(cr, uid, ids)
- for picking in self.browse(cr, uid, ids):
- todo = []
- todo.extend( filter( lambda r: r.location_dest_id.chained_location_type, picking.move_lines) )
- if todo:
- loc = self.pool.get('stock.location').chained_location_get(cr, uid, todo[0].location_dest_id, todo[0].picking_id and todo[0].picking_id.address_id and todo[0].picking_id.address_id.partner_id, todo[0].product_id)
- ptype = self.pool.get('stock.location').picking_type_get(cr, uid, todo[0].location_dest_id, loc)
- pickid = self.pool.get('stock.picking').create(cr, uid, {
- 'name': picking.name,
- 'origin': str(picking.origin or ''),
- 'type': ptype,
- 'note': picking.note,
- 'move_type': picking.move_type,
- 'auto_picking': todo[0].location_dest_id.chained_auto_packing,
- 'address_id': picking.address_id.id,
- 'invoice_state': 'none'
- })
- for move in todo:
- loc = self.pool.get('stock.location').chained_location_get(cr, uid, move.location_dest_id, picking.address_id.partner_id, move.product_id).id
- new_id = self.pool.get('stock.move').copy(cr, uid, move.id, {
- 'location_id': move.location_dest_id.id,
- 'location_dest_id': loc,
- 'date_moved': time.strftime('%Y-%m-%d'),
- 'picking_id': pickid,
- 'state':'waiting',
- 'prodlot_id':False,
- 'tracking_id':False,
- 'move_history_ids':[],
- 'date_planned': DateTime.strptime(move.date_planned, '%Y-%m-%d') + DateTime.RelativeDateTime(days=move.location_dest_id.chained_delay or 0),
- 'move_history_ids2':[]}
- )
- self.pool.get('stock.move').write(cr, uid, [move.id], {
- 'move_dest_id': new_id,
- 'move_history_ids': [(4, new_id)]
- })
- wf_service = netsvc.LocalService("workflow")
- wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
+ self.pool.get('stock.move').action_confirm(cr,uid, todo, context)
return True
def test_auto_picking(self, cr, uid, ids):
@@ -762,7 +717,23 @@ class stock_move(osv.osv):
'price_unit': fields.float('Unit Price',
digits=(16, int(config['price_accuracy']))),
}
+ def _default_location_destination(self, cr, uid, context={}):
+ if context.get('move_line', []):
+ return context['move_line'][0][2]['location_dest_id']
+ if context.get('address_out_id', False):
+ return self.pool.get('res.partner.address').browse(cr, uid, context['address_out_id'], context).partner_id.property_stock_customer.id
+ return False
+
+ def _default_location_source(self, cr, uid, context={}):
+ if context.get('move_line', []):
+ return context['move_line'][0][2]['location_id']
+ if context.get('address_in_id', False):
+ return self.pool.get('res.partner.address').browse(cr, uid, context['address_in_id'], context).partner_id.property_stock_supplier.id
+ return False
+
_defaults = {
+ 'location_id': _default_location_source,
+ 'location_dest_id': _default_location_destination,
'state': lambda *a: 'draft',
'priority': lambda *a: '1',
'product_qty': lambda *a: 1.0,
@@ -795,9 +766,55 @@ class stock_move(osv.osv):
result['location_dest_id'] = loc_dest_id
return {'value':result}
- def action_confirm(self, cr, uid, ids, context={}):
+ def _chain_compute(self, cr, uid, moves, context={}):
+ result = {}
+ for m in moves:
+ dest = self.pool.get('stock.location').chained_location_get(cr, uid, m.location_dest_id, m.picking_id and m.picking_id.address_id and m.picking_id.address_id.partner_id, m.product_id, context)
+ if dest:
+ if dest[1]=='transparent':
+ self.write(cr, uid, [m.id], {
+ 'date_planned': (DateTime.strptime(m.date_planned, '%Y-%m-%d') + \
+ DateTime.RelativeDateTime(days=dest[2] or 0)).strftime('%Y-%m-%d'),
+ 'location_dest_id': dest[0].id})
+ else:
+ result.setdefault(m.picking_id, [])
+ result[m.picking_id].append( (m, dest) )
+ return result
+
+ def action_confirm(self, cr, uid, moves, context={}):
+ ids = map(lambda m: m.id, moves)
self.write(cr, uid, ids, {'state':'confirmed'})
- return True
+ for picking, todo in self._chain_compute(cr, uid, moves, context).items():
+ ptype = self.pool.get('stock.location').picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
+ pickid = self.pool.get('stock.picking').create(cr, uid, {
+ 'name': picking.name,
+ 'origin': str(picking.origin or ''),
+ 'type': ptype,
+ 'note': picking.note,
+ 'move_type': picking.move_type,
+ 'auto_picking': todo[0][1][1]=='auto',
+ 'address_id': picking.address_id.id,
+ 'invoice_state': 'none'
+ })
+ for move,(loc,auto,delay) in todo:
+ # Is it smart to copy ? May be it's better to recreate ?
+ new_id = self.pool.get('stock.move').copy(cr, uid, move.id, {
+ 'location_id': move.location_dest_id.id,
+ 'location_dest_id': loc.id,
+ 'date_moved': time.strftime('%Y-%m-%d'),
+ 'picking_id': pickid,
+ 'state':'waiting',
+ 'move_history_ids':[],
+ 'date_planned': (DateTime.strptime(move.date_planned, '%Y-%m-%d') + DateTime.RelativeDateTime(days=delay or 0)).strftime('%Y-%m-%d'),
+ 'move_history_ids2':[]}
+ )
+ self.pool.get('stock.move').write(cr, uid, [move.id], {
+ 'move_dest_id': new_id,
+ 'move_history_ids': [(4, new_id)]
+ })
+ wf_service = netsvc.LocalService("workflow")
+ wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
+ return []
def action_assign(self, cr, uid, ids, *args):
todo = []
@@ -1092,63 +1109,6 @@ class stock_warehouse(osv.osv):
stock_warehouse()
-# Product
-class product_product(osv.osv):
- _inherit = "product.product"
- #
- # Utiliser browse pour limiter les queries !
- #
- def view_header_get(self, cr, user, view_id, view_type, context):
- res = super(product_product, self).view_header_get(cr, user, view_id, view_type, context)
- if res: return res
- if (not context.get('location', False)):
- return False
- cr.execute('select name from stock_location where id=%d', (context['location'],))
- j = cr.fetchone()[0]
- if j:
- return 'Products: '+j
- return False
-
- def _get_product_available_func(states, what):
- def _product_available(self, cr, uid, ids, name, arg, context={}):
- if context.get('shop', False):
- cr.execute('select warehouse_id from sale_shop where id=%d', (int(context['shop']),))
- res2 = cr.fetchone()
- if res2:
- context['warehouse'] = res2[0]
-
- if context.get('warehouse', False):
- cr.execute('select lot_stock_id from stock_warehouse where id=%d', (int(context['warehouse']),))
- res2 = cr.fetchone()
- if res2:
- context['location'] = res2[0]
-
- if context.get('location', False):
- location_ids = [context['location']]
- else:
- # get the list of ids of the stock location of all warehouses
- cr.execute("select lot_stock_id from stock_warehouse")
- location_ids = [id for (id,) in cr.fetchall()]
-
- # build the list of ids of children of the location given by id
- location_ids = self.pool.get('stock.location').search(cr, uid, [('location_id', 'child_of', location_ids)])
- res = self.pool.get('stock.location')._product_get_multi_location(cr, uid, location_ids, ids, context, states, what)
- for id in ids:
- res.setdefault(id, 0.0)
- return res
- return _product_available
- _product_qty_available = _get_product_available_func(('done',), ('in', 'out'))
- _product_virtual_available = _get_product_available_func(('confirmed','waiting','assigned','done'), ('in', 'out'))
- _product_outgoing_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('out',))
- _product_incoming_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('in',))
- _columns = {
- 'qty_available': fields.function(_product_qty_available, method=True, type='float', string='Real Stock'),
- 'virtual_available': fields.function(_product_virtual_available, method=True, type='float', string='Virtual Stock'),
- 'incoming_qty': fields.function(_product_incoming_qty, method=True, type='float', string='Incoming'),
- 'outgoing_qty': fields.function(_product_outgoing_qty, method=True, type='float', string='Outgoing'),
- }
-product_product()
-
# Move wizard :
# get confirm or assign stock move lines of partner and put in current picking.
class stock_picking_move_wizard(osv.osv_memory):
diff --git a/addons/stock/stock_sequence.xml b/addons/stock/stock_sequence.xml
index b5fd1fb138d..6c0871e8e6c 100644
--- a/addons/stock/stock_sequence.xml
+++ b/addons/stock/stock_sequence.xml
@@ -1,42 +1,24 @@
-
+
+ Sequences for packings
+ -->
-
- Packing Out
- stock.picking.out
+
+ Packing
+ stock.picking
-
- Packing In
- stock.picking.in
-
-
- Packing Internal
- stock.picking.internal
-
-
-
- Packing Out
- stock.picking.out
- OUT:
-
-
- Packing In
- stock.picking.in
- IN:
-
-
- Packing Internal
- stock.picking.internal
- INTERNAL:
+
+
+ Packing
+ stock.picking
+ PACK
+ Sequences from tracking numbers
+ -->
Stock Production Lots
stock.lot.serial
@@ -44,7 +26,7 @@
Stock Production Lots
stock.lot.serial
- 1234567890
+
7
1
1
@@ -59,10 +41,10 @@
Stock Tracking Lots
stock.lot.tracking
- 1234567890
+
7
1
1
-
\ No newline at end of file
+
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index baa82530fdd..3428665bd78 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -28,8 +28,8 @@
@@ -313,7 +313,7 @@
-
+
@@ -391,7 +391,7 @@
-
+
@@ -405,7 +405,7 @@
-
+
@@ -427,7 +427,7 @@
form