Improved:
Sales Management Project Manegement Stock Management Accounting bzr revid: fp@tinyerp.com-20080907232439-bod5fedw3o7w7u47
This commit is contained in:
parent
426bc5164e
commit
c949d120fc
|
@ -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')<fy.date_stop:
|
||||
de = ds + RelativeDateTime(months=interval, days=-1)
|
||||
self.pool.get('account.period').create(cr, uid, {
|
||||
'name': ds.strftime('%d/%m') + ' - '+de.strftime('%d/%m'),
|
||||
'code': ds.strftime('%d/%m') + '-'+de.strftime('%d/%m'),
|
||||
'name': ds.strftime('%m/%Y'),
|
||||
'code': ds.strftime('%m/%Y'),
|
||||
'date_start': ds.strftime('%Y-%m-%d'),
|
||||
'date_stop': de.strftime('%Y-%m-%d'),
|
||||
'fiscalyear_id': fy.id,
|
||||
|
|
|
@ -5,10 +5,6 @@
|
|||
<test expr="not len(line_id) or line_id[0].state != 'valid' or (sum([l.debit - l.credit for l in line_id]) <= 0.00001)"/>
|
||||
</assert>
|
||||
|
||||
<!--assert model="account.invoice" search="[]" string="If the invoice is paid, third party accounting lines must be reconciled">
|
||||
<test expr="not state == 'paid' or ..." />
|
||||
</assert-->
|
||||
|
||||
<assert model="account.account" search="[]" string="For all accounts, the balance is equal to the sum of the balance of its childs">
|
||||
<test expr="not len(child_id) or (balance - sum([c.balance for c in child_id]) <= 0.00001)"/>
|
||||
</assert>
|
||||
|
@ -29,4 +25,4 @@
|
|||
<test expr="not parent_id or (code!='0')"/>
|
||||
</assert>
|
||||
</data>
|
||||
</terp>
|
||||
</terp>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1411,7 +1411,7 @@
|
|||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">account.config.fiscalyear</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ your own chart of account.
|
|||
<record id="cash" model="account.account">
|
||||
<field name="name">Petty Cash</field>
|
||||
<field name="code">x 570000</field>
|
||||
<field name="type">cash</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.account_type_cash_moves"/>
|
||||
<field eval="ref('minimal_0')" name="parent_id"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
|
@ -64,7 +64,7 @@ your own chart of account.
|
|||
<record id="a_expense" model="account.account">
|
||||
<field name="name">Products Purchase</field>
|
||||
<field name="code">x 600000</field>
|
||||
<field name="type">expense</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.account_type_expense"/>
|
||||
<field eval="ref('minimal_0')" name="parent_id"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
|
@ -78,7 +78,7 @@ your own chart of account.
|
|||
<record id="a_sale" model="account.account">
|
||||
<field name="name">Products Sales</field>
|
||||
<field name="code">x 701000</field>
|
||||
<field name="type">income</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.account_type_income"/>
|
||||
<field eval="ref('minimal_0')" name="parent_id"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -150,16 +150,16 @@
|
|||
<field name="total_difference" widget="float_time"/>
|
||||
</page>
|
||||
<!--
|
||||
<page string="By account">
|
||||
<field name="account_ids" colspan="4" nolabel="1">
|
||||
<tree string="Analytic accounts">
|
||||
<field name="name"/>
|
||||
<field name="total" widget="float_time"/>
|
||||
<field name="invoice_rate"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
-->
|
||||
<page string="By account">
|
||||
<field name="account_ids" colspan="4" nolabel="1">
|
||||
<tree string="Analytic accounts">
|
||||
<field name="name"/>
|
||||
<field name="total" widget="float_time"/>
|
||||
<field name="invoice_rate"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
-->
|
||||
</notebook>
|
||||
<field name="state"/>
|
||||
<group col="4" colspan="2">
|
||||
|
@ -238,8 +238,8 @@
|
|||
<menuitem action="act_hr_timesheet_sheet_form_all_valid" id="menu_act_hr_timesheet_sheet_form_all_valid" parent="hr_timesheet_sheet.menu_act_hr_timesheet_sheet_form"/>
|
||||
|
||||
<!--
|
||||
Company inheritancy
|
||||
-->
|
||||
Company inheritancy
|
||||
-->
|
||||
|
||||
<record id="hr_timesheet_sheet_company" model="ir.ui.view">
|
||||
<field name="name">res.company.sheet</field>
|
||||
|
@ -247,18 +247,18 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="rml_footer2" position="after">
|
||||
<newline/>
|
||||
<page string="Configuration" position="inside">
|
||||
<separator string="Timesheets" colspan="4"/>
|
||||
<field name="timesheet_range"/>
|
||||
<field name="timesheet_max_difference"/>
|
||||
<newline/>
|
||||
</field>
|
||||
</page>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
hr.analytic.timesheet inheritancy
|
||||
-->
|
||||
hr.analytic.timesheet inheritancy
|
||||
-->
|
||||
|
||||
<record id="hr_timesheet_line_form" model="ir.ui.view">
|
||||
<field name="name">hr.analytic.timesheet.form</field>
|
||||
|
@ -271,10 +271,9 @@
|
|||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
hr.attendance inheritancy
|
||||
-->
|
||||
hr.attendance inheritancy
|
||||
-->
|
||||
|
||||
<record id="view_attendance_form" model="ir.ui.view">
|
||||
<field name="name">hr.attendance.form</field>
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -170,7 +170,7 @@
|
|||
<field name="name">product.category.list</field>
|
||||
<field name="model">product.category</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="sequence">1</field>
|
||||
<field name="priority">1</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Product Categories">
|
||||
<field name="complete_name"/>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
<field name="active" select="2"/>
|
||||
<button name="toggleActive" string="Toggle activity" type="object"/>
|
||||
</group>
|
||||
<field name="warn_manager"/>
|
||||
<newline/>
|
||||
<field name="planned_hours" widget="float_time"/>
|
||||
<field name="effective_hours" widget="float_time"/>
|
||||
<field name="warn_manager"/>
|
||||
<field name="timesheet_id"/>
|
||||
<field name="state"/>
|
||||
<newline/>
|
||||
<separator colspan="4" string="Project's members"/>
|
||||
<field colspan="4" name="members" nolabel="1"/>
|
||||
</page>
|
||||
|
@ -209,18 +209,25 @@
|
|||
<field eval="2" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Task edition">
|
||||
<field name="name" select="1"/>
|
||||
<field name="project_id" required="1" select="1"/>
|
||||
<field name="user_id" select="1"/>
|
||||
<field name="planned_hours" widget="float_time"/>
|
||||
<group colspan="6" col="6">
|
||||
<field name="name" select="1"/>
|
||||
<field name="project_id" required="1" select="1"/>
|
||||
<field name="total_hours" widget="float_time"/>
|
||||
<field name="user_id" select="1"/>
|
||||
<field name="date_deadline" select="2"/>
|
||||
<field name="progress" widget="progressbar"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Information">
|
||||
<field name="date_deadline" select="2"/>
|
||||
<field name="priority"/>
|
||||
<separator colspan="4" string="Description"/>
|
||||
<field colspan="4" name="description" nolabel="1" select="2"/>
|
||||
<field
|
||||
name="planned_hours"
|
||||
widget="float_time"
|
||||
on_change="onchange_planned(planned_hours,effective_hours)"/>
|
||||
<field name="delay_hours" widget="float_time"/>
|
||||
<field name="remaining_hours" select="2" widget="float_time"/>
|
||||
<field name="effective_hours" widget="float_time"/>
|
||||
<field name="progress"/>
|
||||
|
||||
<field colspan="4" name="description" nolabel="1" select="2"/>
|
||||
<field colspan="4" name="work_ids" nolabel="1"/>
|
||||
<newline/>
|
||||
<group col="11" colspan="4">
|
||||
|
@ -250,10 +257,14 @@
|
|||
<field colspan="4" name="parent_id"/>
|
||||
</page>
|
||||
<page groups="base.group_extended" string="Extra Info">
|
||||
<separator string="Planning" colspan="2"/>
|
||||
<separator string="Dates" colspan="2"/>
|
||||
<field name="priority"/>
|
||||
<field name="date_start" select="2"/>
|
||||
<field name="date_close" select="2"/>
|
||||
<field name="type"/>
|
||||
<field name="sequence"/>
|
||||
<field name="date_close" select="2"/>
|
||||
|
||||
<field name="type"/>
|
||||
<field name="active" select="2"/>
|
||||
<field name="start_sequence"/>
|
||||
<field name="partner_id" select="2"/>
|
||||
|
@ -270,17 +281,18 @@
|
|||
<field name="type">tree</field>
|
||||
<field eval="2" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree colors="grey:state in ('cancel','done');blue:state=='pending'" string="Tasks">
|
||||
<tree colors="grey:state in ('cancel','done');blue:remaining_hours<0;red:bool(date_deadline) & (date_deadline<current_date) & (state in ('draft','open'))" string="Tasks">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="project_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="date_deadline"/>
|
||||
<field name="planned_hours" sum="Planned hours" widget="float_time"/>
|
||||
<field name="effective_hours" sum="Effective hours" widget="float_time"/>
|
||||
<field name="planned_hours" sum="Planned" widget="float_time"/>
|
||||
<field name="delay_hours" sum="Delay" widget="float_time"/>
|
||||
<field name="progress" widget="progressbar"/>
|
||||
<field name="priority"/>
|
||||
<field name="state"/>
|
||||
<field name="remaining_hours" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -444,6 +456,20 @@
|
|||
view_mode="tree,form,calendar"
|
||||
view_type="form"/>
|
||||
|
||||
<record id="task_company" model="ir.ui.view">
|
||||
<field name="name">res.company.task.config</field>
|
||||
<field name="model">res.company</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<page string="Configuration" position="inside">
|
||||
<separator string="Project Management" colspan="4"/>
|
||||
<field name="project_time_mode"/>
|
||||
<newline/>
|
||||
</page>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window domain="[('user_id', '=', active_id),('state', '<>', 'cancelled'),('state', '<>', 'done')]" id="act_res_users_2_project_task_opened" name="Assigned tasks" res_model="project.task" src_model="res.users" view_mode="tree,form" view_type="form"/>
|
||||
|
||||
<act_window domain="[('user_id', '=', active_id),('date', '>=', time.strftime('%Y-%m-01'))]" id="act_res_users_2_project_task_work_month" name="Month works" res_model="project.task.work" src_model="res.users" view_mode="tree,form" view_type="form"/>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<terp>
|
||||
<data>
|
||||
<wizard id="wizard_billing" model="project.task" name="project.wiz_bill" string="Bill tasks"/>
|
||||
<wizard id="wizard_close_task" menu="False" model="project.task" name="project.task.close" string="Close Task"/>
|
||||
<wizard id="wizard_delegate_task" menu="False" model="project.task" name="project.task.delegate" string="Delegate Task"/>
|
||||
</data>
|
||||
</terp>
|
||||
</terp>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -91,9 +91,24 @@
|
|||
<notebook>
|
||||
<page string="Order Line">
|
||||
<separator colspan="4" string="Automatic Declaration"/>
|
||||
<field colspan="4" context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom" name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], True, parent.date_order)" select="1"/>
|
||||
<field context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom" name="product_uom_qty" on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], False, parent.date_order)" select="1"/>
|
||||
<field name="product_uom" on_change="product_uom_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], False, parent.date_order)"/>
|
||||
<field colspan="4"
|
||||
context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom"
|
||||
name="product_id"
|
||||
on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], True, parent.date_order, product_packaging)"
|
||||
select="1"/>
|
||||
<field
|
||||
context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom"
|
||||
name="product_uom_qty"
|
||||
on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], False, parent.date_order, product_packaging)"
|
||||
select="1"/>
|
||||
<field name="product_uom"
|
||||
on_change="product_uom_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], False, parent.date_order)"/>
|
||||
<field
|
||||
name="product_packaging"
|
||||
context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom"
|
||||
on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], False, parent.date_order, product_packaging)"
|
||||
domain="[('product_id','=',product_id)]"
|
||||
groups="base.group_extended"/>
|
||||
<separator colspan="4" string="Manual Description"/>
|
||||
<field colspan="4" name="name" select="2"/>
|
||||
<field name="price_unit" select="2"/>
|
||||
|
@ -112,7 +127,6 @@
|
|||
<page groups="base.group_extended" string="Extra Info">
|
||||
<field groups="product.group_uos" name="product_uos_qty" on_change="uos_change(product_uos, product_uos_qty, product_id)"/>
|
||||
<field groups="product.group_uos" name="product_uos"/>
|
||||
<field name="product_packaging"/>
|
||||
<field name="address_allotment_id" select="2"/>
|
||||
<separator colspan="4" string="Properties"/>
|
||||
<field colspan="4" name="property_ids" nolabel="1"/>
|
||||
|
@ -209,7 +223,7 @@
|
|||
<menuitem action="action_order_tree_all" id="menu_action_order_tree_all" parent="sale.menu_sale_order"/>
|
||||
|
||||
<record id="action_order_tree_new" model="ir.actions.act_window">
|
||||
<field name="name">New Sale Order / Quotation</field>
|
||||
<field name="name">New Quotation</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_type">form</field>
|
||||
|
|
|
@ -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
|
||||
|
|
|
|
@ -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'
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
<field name="model">product.product</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="product.product_normal_form_view"/>
|
||||
<field name="priority">26</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="property_account_expense" position="after">
|
||||
<field name="property_stock_account_input"/>
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1,42 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<terp>
|
||||
<data noupdate="1">
|
||||
<data>
|
||||
<!--
|
||||
Sequences for packings
|
||||
-->
|
||||
Sequences for packings
|
||||
-->
|
||||
|
||||
<record id="seq_type_picking_out" model="ir.sequence.type">
|
||||
<field name="name">Packing Out</field>
|
||||
<field name="code">stock.picking.out</field>
|
||||
<record id="seq_type_picking" model="ir.sequence.type">
|
||||
<field name="name">Packing</field>
|
||||
<field name="code">stock.picking</field>
|
||||
</record>
|
||||
<record id="seq_type_picking_in" model="ir.sequence.type">
|
||||
<field name="name">Packing In</field>
|
||||
<field name="code">stock.picking.in</field>
|
||||
</record>
|
||||
<record id="seq_type_picking_internal" model="ir.sequence.type">
|
||||
<field name="name">Packing Internal</field>
|
||||
<field name="code">stock.picking.internal</field>
|
||||
</record>
|
||||
|
||||
<record id="seq_picking_out" model="ir.sequence">
|
||||
<field name="name">Packing Out</field>
|
||||
<field name="code">stock.picking.out</field>
|
||||
<field name="prefix">OUT:</field>
|
||||
</record>
|
||||
<record id="seq_picking_in" model="ir.sequence">
|
||||
<field name="name">Packing In</field>
|
||||
<field name="code">stock.picking.in</field>
|
||||
<field name="prefix">IN:</field>
|
||||
</record>
|
||||
<record id="seq_picking_internal" model="ir.sequence">
|
||||
<field name="name">Packing Internal</field>
|
||||
<field name="code">stock.picking.internal</field>
|
||||
<field name="prefix">INTERNAL:</field>
|
||||
|
||||
<record id="seq_picking" model="ir.sequence">
|
||||
<field name="name">Packing</field>
|
||||
<field name="code">stock.picking</field>
|
||||
<field name="prefix">PACK</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Sequences from tracking numbers
|
||||
-->
|
||||
Sequences from tracking numbers
|
||||
-->
|
||||
<record id="sequence_type_serial" model="ir.sequence.type">
|
||||
<field name="name">Stock Production Lots</field>
|
||||
<field name="code">stock.lot.serial</field>
|
||||
|
@ -44,7 +26,7 @@
|
|||
<record id="sequence_production_lots" model="ir.sequence">
|
||||
<field name="name">Stock Production Lots</field>
|
||||
<field name="code">stock.lot.serial</field>
|
||||
<field name="prefix">1234567890</field>
|
||||
<field name="prefix"></field>
|
||||
<field name="padding">7</field>
|
||||
<field name="number_next">1</field>
|
||||
<field name="number_increment">1</field>
|
||||
|
@ -59,10 +41,10 @@
|
|||
<record id="sequence_tracking" model="ir.sequence">
|
||||
<field name="name">Stock Tracking Lots</field>
|
||||
<field name="code">stock.lot.tracking</field>
|
||||
<field name="prefix">1234567890</field>
|
||||
<field name="prefix"></field>
|
||||
<field name="padding">7</field>
|
||||
<field name="number_next">1</field>
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
</data>
|
||||
</terp>
|
||||
</terp>
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
<form string="Stock Inventory Lines">
|
||||
<field colspan="4" domain="[('usage','=','internal')]" name="location_id" select="1"/>
|
||||
<field context="location=location_id,uom=product_uom" name="product_id" on_change="on_change_product_id(location_id,product_id,product_uom)" select="1"/>
|
||||
<field name="product_uom"/>
|
||||
<field name="product_qty"/>
|
||||
<field name="product_uom"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -313,7 +313,7 @@
|
|||
<field name="usage" select="1"/>
|
||||
<field name="account_id" select="1"/>
|
||||
<field name="location_id"/>
|
||||
<field name="address_id"/>
|
||||
<field name="address_id" context="{'context_display':'partner'}"/>
|
||||
<group col="2" colspan="2">
|
||||
<separator string="Chained Locations" colspan="2"/>
|
||||
<field name="chained_location_type"/>
|
||||
|
@ -391,7 +391,7 @@
|
|||
<field name="lot_stock_id"/>
|
||||
<field name="lot_output_id"/>
|
||||
<newline/>
|
||||
<field name="partner_address_id"/>
|
||||
<field name="partner_address_id" context="{'context_display':'partner'}"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -405,7 +405,7 @@
|
|||
<field name="lot_input_id"/>
|
||||
<field name="lot_stock_id"/>
|
||||
<field name="lot_output_id"/>
|
||||
<field name="partner_address_id"/>
|
||||
<field name="partner_address_id" context="{'context_display':'partner'}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -427,7 +427,7 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Move Lines">
|
||||
<field name="address_id" invisible="True"/>
|
||||
<field name="address_id" invisible="True" context="{'context_display':'partner'}"/>
|
||||
<field name="picking_id" invisible="True"/>
|
||||
<field domain="[('picking_id','<>',picking_id),('state','in',['confirmed','assigned'])]" name="move_ids" select="1"/><newline/>
|
||||
<group colspan="4">
|
||||
|
@ -461,7 +461,7 @@
|
|||
<tree color="red:state=='cancel'" string="Packing list">
|
||||
<field colspan="4" name="name" select="1"/>
|
||||
<field name="date" select="1"/>
|
||||
<field name="address_id" select="1"/>
|
||||
<field name="address_id" select="1" context="{'context_display':'partner'}"/>
|
||||
<field name="invoice_state" readonly="1"/>
|
||||
<field name="origin" select="1"/>
|
||||
<field name="state" readonly="1"/>
|
||||
|
@ -476,37 +476,31 @@
|
|||
<form string="Packing list">
|
||||
<notebook>
|
||||
<page string="General Information">
|
||||
<field name="name" select="1"/>
|
||||
<field name="address_id" select="2" context="{'context_display':'partner'}"/>
|
||||
<field name="type" select="2" readonly="1"/>
|
||||
<field name="name" select="1" readonly="1"/>
|
||||
<field name="date" select="1"/>
|
||||
<newline/>
|
||||
<field name="type" select="2"/>
|
||||
<field name="invoice_state" select="2"/>
|
||||
<newline/>
|
||||
<field name="location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="address_id" select="2"/>
|
||||
<field colspan="4" name="move_lines" nolabel="1" widget="one2many_list">
|
||||
<field colspan="4" name="move_lines" nolabel="1" widget="one2many_list" default_get="{'move_line':move_lines, 'address_out_id': address_id}">
|
||||
<form string="Stock Moves">
|
||||
<separator colspan="4" string="Move Information"/>
|
||||
<field colspan="4" context="location=parent.location_id" name="product_id" on_change="onchange_product_id(product_id, parent.location_id, parent.location_dest_id)" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field name="location_id" select="1" domain="[('usage','=','internal')]"/>
|
||||
<field name="location_dest_id" select="1" domain="[('usage','=','internal')]"/>
|
||||
<field colspan="4" context="location=location_id" name="product_id" on_change="onchange_product_id(product_id, location_id, location_dest_id)" select="1"/>
|
||||
<field name="product_qty" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field groups="product.group_uos" name="product_uos"/>
|
||||
<field groups="product.group_uos" name="product_uos_qty"/>
|
||||
<field colspan="4" name="name" select="1"/>
|
||||
<field name="date"/>
|
||||
<field colspan="4" invisible="1" name="name" select="1"/>
|
||||
<field invisible="1" name="date"/>
|
||||
<field name="date_planned"/>
|
||||
<field name="priority"/>
|
||||
<field name="location_id" select="1"/>
|
||||
<field name="location_dest_id" select="1"/>
|
||||
<field name="address_id" select="1"/>
|
||||
<field name="product_packaging"/>
|
||||
<field name="address_id" select="1" context="{'context_display':'partner'}"/>
|
||||
<field groups="base.group_extended" name="product_packaging"/>
|
||||
<field context="product_id=product_id" name="prodlot_id" select="1"/>
|
||||
<field name="tracking_id" select="1"/>
|
||||
<field groups="base.group_extended" name="tracking_id" select="1"/>
|
||||
<newline/>
|
||||
<label/>
|
||||
<button name="%(track_line)d" string="Split in production lots" type="action"/>
|
||||
|
||||
<separator colspan="4" string="Move State"/>
|
||||
<field name="state" select="1"/>
|
||||
<group>
|
||||
|
@ -556,7 +550,7 @@
|
|||
<tree color="red:state=='cancel'" string="Packing list">
|
||||
<field colspan="4" name="name" select="1"/>
|
||||
<field name="date" select="1"/>
|
||||
<field name="address_id" select="1"/>
|
||||
<field name="address_id" select="1" context="{'context_display':'partner'}"/>
|
||||
<field name="origin" select="1"/>
|
||||
<field name="state" readonly="1"/>
|
||||
</tree>
|
||||
|
@ -568,26 +562,25 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Packing list">
|
||||
<field name="name" select="1"/>
|
||||
<field name="date" select="1"/>
|
||||
<newline/>
|
||||
<field name="address_id" select="2"/>
|
||||
<field name="address_id" select="2" context="{'context_display':'partner'}"/>
|
||||
<field name="origin" select="2"/>
|
||||
<field name="name" select="1" readonly="1"/>
|
||||
<field name="date" select="1" readonly="1"/>
|
||||
<notebook colspan="4">
|
||||
<page string="General Information">
|
||||
<field colspan="4" name="move_lines" nolabel="1" widget="one2many_list">
|
||||
<field colspan="4" name="move_lines" nolabel="1" widget="one2many_list" default_get="{'move_line':move_lines, 'address_out_id': address_id}">
|
||||
<form string="Stock Moves">
|
||||
<separator colspan="4" string="Move Information"/>
|
||||
<field colspan="4" context="location=parent.location_id" name="product_id" on_change="onchange_product_id(product_id, parent.location_id, parent.location_dest_id)" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field name="location_id" select="1" domain="[('usage','=','internal')]"/>
|
||||
<field name="location_dest_id" select="1" domain="[('usage','<>','view')]"/>
|
||||
<field colspan="4" context="location=location_id" name="product_id" on_change="onchange_product_id(product_id, location_id, location_dest_id)" select="1"/>
|
||||
<field name="product_qty" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field groups="product.group_uos" name="product_uos"/>
|
||||
<field groups="product.group_uos" name="product_uos_qty"/>
|
||||
<field colspan="4" invisible="1" name="name" select="1"/>
|
||||
<field invisible="1" name="date"/>
|
||||
<field name="date_planned"/>
|
||||
<field name="location_id" select="1"/>
|
||||
<field name="location_dest_id" select="1"/>
|
||||
<field groups="base.group_extended" name="product_packaging"/>
|
||||
<field context="product_id=product_id" name="prodlot_id" select="1"/>
|
||||
<field groups="base.group_extended" name="tracking_id" select="1"/>
|
||||
|
@ -710,7 +703,7 @@
|
|||
<tree color="red:state=='cancel'" string="Packing list">
|
||||
<field colspan="4" name="name" select="1"/>
|
||||
<field name="date" select="1"/>
|
||||
<field name="address_id" select="1"/>
|
||||
<field name="address_id" select="1" context="{'context_display':'partner'}"/>
|
||||
<field name="invoice_state" readonly="1"/>
|
||||
<field name="origin" select="1"/>
|
||||
<field name="state" readonly="1"/>
|
||||
|
@ -723,26 +716,25 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Packing list">
|
||||
<field name="name" select="1"/>
|
||||
<field name="date" select="1"/>
|
||||
<newline/>
|
||||
<field name="address_id" select="2"/>
|
||||
<field name="address_id" select="2" context="{'context_display':'partner'}"/>
|
||||
<field name="date" select="1" readonly="1"/>
|
||||
<field name="origin" select="2"/>
|
||||
<field name="name" select="1" readonly="1"/>
|
||||
<notebook colspan="4">
|
||||
<page string="General Information">
|
||||
<field colspan="4" name="move_lines" nolabel="1" widget="one2many_list">
|
||||
<field colspan="4" name="move_lines" nolabel="1" widget="one2many_list" default_get="{'move_line':move_lines, 'address_out_id': address_id}">
|
||||
<form string="Stock Moves">
|
||||
<separator colspan="4" string="Move Information"/>
|
||||
<field colspan="4" context="location=parent.location_id" name="product_id" on_change="onchange_product_id(product_id, parent.location_id, parent.location_dest_id)" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field name="location_id" select="1" domain="[('usage','=','internal')]"/>
|
||||
<field name="location_dest_id" select="1" domain="[('usage','<>','view')]"/>
|
||||
<field colspan="4" context="location=location_id" name="product_id" on_change="onchange_product_id(product_id, location_id, location_dest_id)" select="1"/>
|
||||
<field name="product_qty" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field groups="product.group_uos" name="product_uos"/>
|
||||
<field groups="product.group_uos" name="product_uos_qty"/>
|
||||
<field colspan="4" invisible="1" name="name" select="1"/>
|
||||
<field invisible="1" name="date"/>
|
||||
<field name="date_planned"/>
|
||||
<field name="location_id" select="1"/>
|
||||
<field name="location_dest_id" select="1"/>
|
||||
<field groups="base.group_extended" name="product_packaging"/>
|
||||
<field context="product_id=product_id" name="prodlot_id" select="1"/>
|
||||
<field groups="base.group_extended" name="tracking_id" select="1"/>
|
||||
|
@ -862,7 +854,7 @@
|
|||
<tree color="red:state=='cancel'" string="Packing list">
|
||||
<field colspan="4" name="name" select="1"/>
|
||||
<field name="date" select="1"/>
|
||||
<field name="address_id" select="1"/>
|
||||
<field name="address_id" select="1" context="{'context_display':'partner'}"/>
|
||||
<field name="invoice_state" readonly="1"/>
|
||||
<field name="origin" select="1"/>
|
||||
<field name="state" readonly="1"/>
|
||||
|
@ -875,15 +867,13 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Input Packing List">
|
||||
<field name="address_id" on_change="onchange_partner_in(address_id)" select="2"/>
|
||||
<field name="name" readonly="1" select="1"/>
|
||||
<field name="location_id"/>
|
||||
<field domain="[('usage','=','internal')]" name="location_dest_id"/>
|
||||
<field name="invoice_state" select="2" string="Supplier Invoice Control"/>
|
||||
<field name="address_id" on_change="onchange_partner_in(address_id)" select="2" context="{'context_display':'partner'}"/>
|
||||
<field name="origin" select="2"/>
|
||||
<field name="invoice_state" select="2" string="Invoice Control"/>
|
||||
<field name="name" readonly="1" select="1"/>
|
||||
<notebook colspan="4">
|
||||
<page string="General Information">
|
||||
<field colspan="4" name="move_lines" nolabel="1" widget="one2many_list">
|
||||
<field colspan="4" name="move_lines" nolabel="1" widget="one2many_list" default_get="{'move_line':move_lines, 'address_in_id': address_id}">
|
||||
<tree string="Stock Moves">
|
||||
<field name="product_id"/>
|
||||
<field name="product_qty"/>
|
||||
|
@ -894,17 +884,17 @@
|
|||
</tree>
|
||||
<form string="Stock Moves">
|
||||
<separator colspan="4" string="Move Information"/>
|
||||
<field colspan="4" context="location=parent.location_id" name="product_id" on_change="onchange_product_id(product_id, parent.location_id, parent.location_dest_id)" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field name="location_id" select="1" domain="[('usage','<>','view')]"/>
|
||||
<field domain="[('usage','=','internal')]" name="location_dest_id" select="1"/>
|
||||
<field colspan="4" context="location=location_id" name="product_id" on_change="onchange_product_id(product_id, location_id, location_dest_id)" select="1"/>
|
||||
<field name="product_qty" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field groups="product.group_uos" name="product_uos"/>
|
||||
<field groups="product.group_uos" name="product_uos_qty"/>
|
||||
<field colspan="4" invisible="1" name="name" select="1"/>
|
||||
<field groups="base.group_extended" name="date"/>
|
||||
<field groups="base.group_extended" name="date_planned"/>
|
||||
<newline/>
|
||||
<field name="location_id" select="1"/>
|
||||
<field domain="[('usage','=','internal')]" name="location_dest_id" select="1"/>
|
||||
<newline/>
|
||||
<field groups="base.group_extended" name="product_packaging"/>
|
||||
<newline/>
|
||||
|
@ -1099,16 +1089,16 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Stock Moves">
|
||||
<separator colspan="4" string="Move Information"/>
|
||||
<field name="location_id" select="1"/>
|
||||
<field name="location_dest_id" select="1"/>
|
||||
<field colspan="4" name="product_id" select="1"/>
|
||||
<field name="product_qty" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field colspan="4" name="name" select="1"/>
|
||||
<field name="date"/>
|
||||
<field name="date_planned"/>
|
||||
<field colspan="4" name="product_id" select="1"/>
|
||||
<field name="product_uom" select="1"/>
|
||||
<field name="product_qty" select="1"/>
|
||||
<field name="location_id" select="1"/>
|
||||
<field name="location_dest_id" select="1"/>
|
||||
<field name="priority"/>
|
||||
<field name="address_id" select="1"/>
|
||||
<field name="address_id" select="1" context="{'context_display':'partner'}"/>
|
||||
<newline/>
|
||||
<field context="product_id=product_id" name="prodlot_id" select="1"/>
|
||||
<field name="tracking_id" select="1"/>
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 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.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import stock
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name" : "Stock Location Paths",
|
||||
"version" : "1.0",
|
||||
"author" : "Tiny",
|
||||
"depends" : [ "stock"],
|
||||
"category" : "Generic Modules/Inventory Control",
|
||||
"description":"""
|
||||
Manages product's path in locations.
|
||||
|
||||
This module may be usefull for different purposes:
|
||||
* Manages the product in his whole manufacturing chain
|
||||
* Manages different default locations by products
|
||||
* Define paths within the warehouse to route products based on operations:
|
||||
- Quality Control
|
||||
- After Sales Services
|
||||
- Supplier Return
|
||||
* Manage products to be rent.
|
||||
""",
|
||||
"init_xml" : [],
|
||||
"demo_xml" : [],
|
||||
"update_xml" : ["stock_view.xml"],
|
||||
"active": False,
|
||||
"installable": True
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 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.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields,osv
|
||||
import tools
|
||||
import ir
|
||||
import pooler
|
||||
|
||||
class stock_location_path(osv.osv):
|
||||
_name = "stock.location.path"
|
||||
_columns = {
|
||||
'name': fields.char('Operation', size=64),
|
||||
'product_id' : fields.many2one('product.product', 'Products', ondelete='cascade', select=1),
|
||||
'location_from_id' : fields.many2one('stock.location', 'Source Location', ondelete='cascade', select=1),
|
||||
'location_dest_id' : fields.many2one('stock.location', 'Destination Location', ondelete='cascade', select=1),
|
||||
'delay': fields.integer('Delay (days)', help="Number of days to do this transition"),
|
||||
'auto': fields.selection(
|
||||
[('auto','Automatic Move'), ('manual','Manual Operation'),('transparent','Automatic No Step Added')],
|
||||
'Automatic Move',
|
||||
required=True, select=1,
|
||||
help="This is used to define paths the product has to follow within the location tree.\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."
|
||||
),
|
||||
}
|
||||
_defaults = {
|
||||
'auto': lambda *arg: 'auto',
|
||||
'delay': lambda *arg: 1
|
||||
}
|
||||
stock_location_path()
|
||||
|
||||
class product_product(osv.osv):
|
||||
_inherit = 'product.product'
|
||||
_columns = {
|
||||
'path_ids': fields.one2many('stock.location.path', 'product_id',
|
||||
'Location Paths',
|
||||
help="These rules set the right path of the product in the "\
|
||||
"whole location tree.")
|
||||
}
|
||||
product_product()
|
||||
|
||||
class stock_location(osv.osv):
|
||||
_inherit = 'stock.location'
|
||||
def chained_location_get(self, cr, uid, location, partner=None, product=None, context={}):
|
||||
if product:
|
||||
for path in product.path_ids:
|
||||
if path.location_from_id.id == location.id:
|
||||
return path.location_dest_id, path.auto, path.delay
|
||||
return super(stock_location, self).chained_location_get(cr, uid, location, partner, product, contex)
|
||||
stock_location()
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0"?>
|
||||
<terp>
|
||||
<data>
|
||||
|
||||
<record id="stock_location_path_tree" model="ir.ui.view">
|
||||
<field name="name">stock.location.path.tree</field>
|
||||
<field name="model">stock.location.path</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Location Paths">
|
||||
<field name="product_id"/>
|
||||
<field name="location_from_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="stock_location_path_form" model="ir.ui.view">
|
||||
<field name="name">stock.location.path.form</field>
|
||||
<field name="model">stock.location.path</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Location Paths">
|
||||
<field name="name"/>
|
||||
<newline/>
|
||||
<field name="product_id"/>
|
||||
<newline/>
|
||||
<field name="location_from_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="auto"/>
|
||||
<field name="delay"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_normal_form_inherit_location" model="ir.ui.view">
|
||||
<field name="name">product.product.form</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="product.product_normal_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<page string="Procurement & Locations">
|
||||
<field name="path_ids" editable="bottom" colspan="4" nolabel="1">
|
||||
<tree string="Location Paths" editable="bottom">
|
||||
<field name="location_from_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="auto"/>
|
||||
<field name="delay"/>
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</terp>
|
Loading…
Reference in New Issue