The following modules are merged::
addons-extra/product_procurement -> mrp module addons-extra/inventory_merge -> stock addons-extra/product_pricelist_print -> product addons-extra/invoice_payment -> account bzr revid: sahibsofia@gmail.com-20080916114513-7an9yz59hucjmjk8
This commit is contained in:
parent
05f980e2a6
commit
a268fad012
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>addons</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.python.pydev.PyDevBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.python.pydev.pythonNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -209,8 +209,17 @@
|
|||
<field colspan="4" name="comment" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Payments">
|
||||
<field name="move_lines" colspan="4"/>
|
||||
</page>
|
||||
<field name="payment_ids" colspan="4" nolabel="1">
|
||||
<tree string="Payments">
|
||||
<field name="date"/>
|
||||
<field name="ref"/>
|
||||
<field name="name"/>
|
||||
<field name="journal_id"/>
|
||||
<field name="debit"/>
|
||||
<field name="credit"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -283,8 +292,17 @@
|
|||
<field colspan="4" name="comment" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Payments">
|
||||
<field name="move_lines" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
<field name="payment_ids" colspan="4" nolabel="1">
|
||||
<tree string="Payments">
|
||||
<field name="date"/>
|
||||
<field name="ref"/>
|
||||
<field name="name"/>
|
||||
<field name="journal_id"/>
|
||||
<field name="debit"/>
|
||||
<field name="credit"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
@ -126,6 +126,26 @@ class account_invoice(osv.osv):
|
|||
l = map(lambda x: x.id, ids_line)
|
||||
res[id]=[x for x in l if x <> line.id]
|
||||
return res
|
||||
|
||||
def _compute_lines(self, cr, uid, ids, name, args, context={}):
|
||||
result = {}
|
||||
print 'ICI 0'
|
||||
for invoice in self.browse(cr, uid, ids, context):
|
||||
moves = self.move_line_id_payment_get(cr, uid, [invoice.id])
|
||||
src = []
|
||||
print 'ICI 1'
|
||||
lines = []
|
||||
for m in self.pool.get('account.move.line').browse(cr, uid, moves, context):
|
||||
print 'ICI 2'
|
||||
if m.reconcile_id:
|
||||
lines += map(lambda x: x.id, m.reconcile_id.line_id)
|
||||
elif m.reconcile_partial_id:
|
||||
lines += map(lambda x: x.id, m.reconcile_partial_id.line_partial_ids)
|
||||
src.append(m.id)
|
||||
print 'ICI 3'
|
||||
lines = filter(lambda x: x not in src, lines)
|
||||
result[invoice.id] = lines
|
||||
return result
|
||||
|
||||
_name = "account.invoice"
|
||||
_description = 'Invoice'
|
||||
|
@ -182,7 +202,7 @@ class account_invoice(osv.osv):
|
|||
help='The bank account to pay to or to be paid from'),
|
||||
'move_lines':fields.function(_get_lines , method=True,type='many2many' , relation='account.move.line',string='Move Lines'),
|
||||
'residual': fields.function(_amount_residual, method=True, digits=(16,2),string='Residual', store=True),
|
||||
|
||||
'payment_ids': fields.function(_compute_lines, method=True, relation='account.move.line', type="many2many", string='Payments'),
|
||||
}
|
||||
_defaults = {
|
||||
'type': _get_type,
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
import analytic_journal_billing_rate
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
{
|
||||
"name" : "Analytic Journal Billing Rate",
|
||||
"version" : "1.0",
|
||||
"depends" : ["analytic_user_function", "account", "hr_timesheet_invoice"],
|
||||
"author" : "Tiny",
|
||||
"description": """
|
||||
|
||||
This module allows you to define what is the defaut invoicing rate for a specific journal on a given account. This is mostly used when a user encode his timesheet: the values are retrieved and the fields are auto-filled... but the possibility to change these values is still available.
|
||||
|
||||
Obviously if no data has been recorded for the current account, the default value is given as usual by the account data so that this module is perfectly compatible with older configurations.
|
||||
|
||||
""",
|
||||
"website" : "http://tinyerp.com/",
|
||||
"category" : "Generic Modules/Others",
|
||||
"init_xml" : [],
|
||||
"demo_xml" : [],
|
||||
"update_xml" : [
|
||||
"analytic_journal_billing_rate_view.xml",
|
||||
],
|
||||
"active": False,
|
||||
"installable": True
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
from osv import fields,osv
|
||||
from osv import orm
|
||||
|
||||
class analytic_journal_rate_grid(osv.osv):
|
||||
|
||||
_name="analytic_journal_rate_grid"
|
||||
_description= "Relation table between journals and billing rates"
|
||||
_columns={
|
||||
'journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal',required=True,),
|
||||
'account_id': fields.many2one("account.analytic.account", "Analytic Account",required=True,),
|
||||
'rate_id': fields.many2one("hr_timesheet_invoice.factor", "Invoicing Rate",),
|
||||
}
|
||||
|
||||
analytic_journal_rate_grid()
|
||||
|
||||
class account_analytic_account(osv.osv):
|
||||
|
||||
_inherit = "account.analytic.account"
|
||||
_columns = {
|
||||
'journal_rate_ids' : fields.one2many('analytic_journal_rate_grid', 'account_id', 'Invoicing Rate per Journal'),
|
||||
}
|
||||
|
||||
account_analytic_account()
|
||||
|
||||
class hr_analytic_timesheet(osv.osv):
|
||||
|
||||
_inherit = "hr.analytic.timesheet"
|
||||
|
||||
|
||||
def on_change_account_id(self, cr, uid, ids,user_id, account_id, journal_id,unit_amount=0):
|
||||
res = {}
|
||||
if not (account_id):
|
||||
#avoid a useless call to super
|
||||
return res
|
||||
|
||||
if not (journal_id):
|
||||
return super(hr_analytic_timesheet, self).on_change_account_id(cr, uid, ids,user_id, account_id, unit_amount)
|
||||
|
||||
#get the browse record related to journal_id and account_id
|
||||
temp = self.pool.get('analytic_journal_rate_grid').search(cr, uid, [('journal_id', '=', journal_id),('account_id', '=', account_id) ])
|
||||
|
||||
if not temp:
|
||||
#if there isn't any record for this journal_id and account_id
|
||||
return super(hr_analytic_timesheet, self).on_change_account_id(cr, uid, ids,user_id, account_id, unit_amount)
|
||||
else:
|
||||
#get the old values from super and add the value from the new relation analytic_journal_rate_grid
|
||||
r = self.pool.get('analytic_journal_rate_grid').browse(cr, uid, temp)[0]
|
||||
res.setdefault('value',{})
|
||||
res['value']= super(hr_analytic_timesheet, self).on_change_account_id(cr, uid, ids,user_id, account_id,unit_amount)['value']
|
||||
if r.rate_id.id:
|
||||
res['value']['to_invoice'] = r.rate_id.id
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def on_change_journal_id(self, cr, uid, ids,journal_id, account_id):
|
||||
res = {}
|
||||
if not (journal_id and account_id):
|
||||
return res
|
||||
|
||||
#get the browse record related to journal_id and account_id
|
||||
temp = self.pool.get('analytic_journal_rate_grid').search(cr, uid, [('journal_id', '=', journal_id),('account_id', '=', account_id) ])
|
||||
if temp:
|
||||
#add the value from the new relation analytic_user_funct_grid
|
||||
r = self.pool.get('analytic_journal_rate_grid').browse(cr, uid, temp)[0]
|
||||
res.setdefault('value',{})
|
||||
if r.rate_id.id:
|
||||
res['value']['to_invoice'] = r.rate_id.id
|
||||
return res
|
||||
to_invoice = self.pool.get('account.analytic.account').read(cr, uid, [account_id], ['to_invoice'])[0]['to_invoice']
|
||||
if to_invoice:
|
||||
res.setdefault('value',{})
|
||||
res['value']['to_invoice'] = to_invoice[0]
|
||||
|
||||
return res
|
||||
|
||||
hr_analytic_timesheet()
|
||||
|
||||
|
||||
class account_invoice(osv.osv):
|
||||
_inherit = "account.invoice"
|
||||
|
||||
def _get_analityc_lines(self, cr, uid, id):
|
||||
iml = super(account_invoice, self)._get_analityc_lines(cr, uid, id)
|
||||
inv = self.browse(cr, uid, [id])[0]
|
||||
for il in iml:
|
||||
if il['account_analytic_id']:
|
||||
|
||||
#get the browse record related to journal_id and account_id
|
||||
journal_id = il['analytic_lines'][0][2]['journal_id']
|
||||
account_id = il['analytic_lines'][0][2]['account_id']
|
||||
if journal_id and account_id:
|
||||
temp = self.pool.get('analytic_journal_rate_grid').search(cr, uid, [('journal_id', '=', journal_id),('account_id', '=', account_id) ])
|
||||
|
||||
if temp:
|
||||
r = self.pool.get('analytic_journal_rate_grid').browse(cr, uid, temp)[0]
|
||||
il['analytic_lines'][0][2]['to_invoice'] = r.rate_id.id
|
||||
return iml
|
||||
|
||||
account_invoice()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- analytic_journal_rate_grid views -->
|
||||
<record model="ir.ui.view" id="analytic_journal_rate_grid_tree">
|
||||
<field name="name">analytic_journal_rate_grid.tree</field>
|
||||
<field name="model">analytic_journal_rate_grid</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Billing Rate per Journal for this Analytic Account" editable="bottom">
|
||||
<field name="journal_id" required="1"/>
|
||||
<field name="rate_id" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="analytic_journal_rate_grid_form">
|
||||
<field name="name">analytic_journal_rate_grid.form</field>
|
||||
<field name="model">analytic_journal_rate_grid</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Billing Rate per Journal for this Analytic Account" editable="bottom">
|
||||
<field name="journal_id" required="1"/>
|
||||
<field name="rate_id" />
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- account.analytic.account inherited view -->
|
||||
<record model="ir.ui.view" id="view_account_analytic_account_form_inherit">
|
||||
<field name="name">account.analytic.account.form</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="account.view_account_analytic_account_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/notebook/page/field[@name='to_invoice']" position="after">
|
||||
<!--<field name="to_invoice" string="Default Invoicing Percentage"/>-->
|
||||
<field name="journal_rate_ids" colspan="4"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- hr_timesheet_sheet.sheet inherited view -->
|
||||
<record model="ir.ui.view" id="hr_timesheet_sheet_form_inherit">
|
||||
<field name="name">hr.timesheet.sheet.form</field>
|
||||
<field name="model">hr_timesheet_sheet.sheet</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="hr_timesheet_sheet.hr_timesheet_sheet_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/notebook/page/field[@name='timesheet_ids']/tree/field[@name='account_id']" position="replace">
|
||||
<field name="account_id" domain="[('type','=','normal'),('state', '<>', 'close')]" on_change="on_change_account_id(user_id, account_id, journal_id, unit_amount)"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- hr.analytic.timesheet inherited views -->
|
||||
<record model="ir.ui.view" id="hr_timesheet_line_form_inherit">
|
||||
<field name="name">hr.analytic.timesheet.form</field>
|
||||
<field name="model">hr.analytic.timesheet</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/field[@name='account_id']" position="replace">
|
||||
<field name="account_id" domain="[('type','=','normal'),('state', '<>', 'close')]" on_change="on_change_account_id(user_id, account_id, journal_id, unit_amount)" select="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_timesheet_line_form_inherit_2">
|
||||
<field name="name">hr.analytic.timesheet.form</field>
|
||||
<field name="model">hr.analytic.timesheet</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/field[@name='journal_id']" position="replace">
|
||||
<field name="journal_id" select="1" required="1" on_change="on_change_journal_id(journal_id, account_id)"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,5 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
import analytic_user_function
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
{
|
||||
"name" : "Analytic User Function",
|
||||
"version" : "1.0",
|
||||
"depends" : ["hr_timesheet_sheet"],
|
||||
"author" : "Tiny",
|
||||
"description": """
|
||||
|
||||
This module allows you to define what is the defaut function of a specific user on a given account. This is mostly used when a user encode his timesheet: the values are retrieved and the fields are auto-filled... but the possibility to change these values is still available.
|
||||
|
||||
Obviously if no data has been recorded for the current account, the default value is given as usual by the employee data so that this module is perfectly compatible with older configurations.
|
||||
|
||||
""",
|
||||
"website" : "http://tinyerp.com/",
|
||||
"category" : "Generic Modules/Others",
|
||||
"init_xml" : [],
|
||||
"demo_xml" : [],
|
||||
"update_xml" : [
|
||||
"analytic_user_function_view.xml",
|
||||
],
|
||||
"active": False,
|
||||
"installable": True
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
from osv import fields,osv
|
||||
from osv import orm
|
||||
|
||||
class analytic_user_funct_grid(osv.osv):
|
||||
|
||||
_name="analytic_user_funct_grid"
|
||||
_description= "Relation table between users and products on a analytic account"
|
||||
_columns={
|
||||
'user_id': fields.many2one("res.users","User",required=True,),
|
||||
'product_id': fields.many2one("product.product","Product",required=True,),
|
||||
'account_id': fields.many2one("account.analytic.account", "Analytic Account",required=True,),
|
||||
}
|
||||
|
||||
analytic_user_funct_grid()
|
||||
|
||||
|
||||
class account_analytic_account(osv.osv):
|
||||
|
||||
_inherit = "account.analytic.account"
|
||||
_columns = {
|
||||
'user_product_ids' : fields.one2many('analytic_user_funct_grid', 'account_id', 'Users/Products Rel.'),
|
||||
}
|
||||
|
||||
account_analytic_account()
|
||||
|
||||
|
||||
class hr_analytic_timesheet(osv.osv):
|
||||
|
||||
_inherit = "hr.analytic.timesheet"
|
||||
|
||||
|
||||
# Look in account, if no value for the user => look in parent until there is no more parent to look
|
||||
# Take the first found... if nothing found => return False
|
||||
def _get_related_user_account_recursiv(self,cr,uid,user_id,account_id):
|
||||
|
||||
temp=self.pool.get('analytic_user_funct_grid').search(cr, uid, [('user_id', '=', user_id),('account_id', '=', account_id) ])
|
||||
account=self.pool.get('account.analytic.account').browse(cr,uid,account_id)
|
||||
if temp:
|
||||
return temp
|
||||
else:
|
||||
if account.parent_id:
|
||||
return self._get_related_user_account_recursiv(cr,uid,user_id,account.parent_id.id)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def on_change_account_id(self, cr, uid, ids,user_id, account_id, unit_amount=0):
|
||||
#{'value': {'to_invoice': False, 'amount': (-162.0,), 'product_id': 7, 'general_account_id': (5,)}}
|
||||
res = {}
|
||||
if not (account_id):
|
||||
#avoid a useless call to super
|
||||
return res
|
||||
|
||||
if not (user_id):
|
||||
return super(hr_analytic_timesheet, self).on_change_account_id(cr, uid, ids,account_id)
|
||||
|
||||
#get the browse record related to user_id and account_id
|
||||
temp = self._get_related_user_account_recursiv(cr,uid,user_id,account_id)
|
||||
# temp = self.pool.get('analytic_user_funct_grid').search(cr, uid, [('user_id', '=', user_id),('account_id', '=', account_id) ])
|
||||
if not temp:
|
||||
#if there isn't any record for this user_id and account_id
|
||||
return super(hr_analytic_timesheet, self).on_change_account_id(cr, uid, ids,account_id)
|
||||
else:
|
||||
#get the old values from super and add the value from the new relation analytic_user_funct_grid
|
||||
r = self.pool.get('analytic_user_funct_grid').browse(cr, uid, temp)[0]
|
||||
res.setdefault('value',{})
|
||||
res['value']= super(hr_analytic_timesheet, self).on_change_account_id(cr, uid, ids,account_id)['value']
|
||||
res['value']['product_id'] = r.product_id.id
|
||||
res['value']['product_uom_id'] = r.product_id.product_tmpl_id.uom_id.id
|
||||
|
||||
#the change of product has to impact the amount, uom and general_account_id
|
||||
a = r.product_id.product_tmpl_id.property_account_expense.id
|
||||
if not a:
|
||||
a = r.product_id.categ_id.property_account_expense_categ.id
|
||||
if not a:
|
||||
raise osv.except_osv('Error !',
|
||||
'There is no expense account define ' \
|
||||
'for this product: "%s" (id:%d)' % \
|
||||
(r.product_id.name, r.product_id.id,))
|
||||
amount = unit_amount * r.product_id.uom_id._compute_price(cr, uid,
|
||||
r.product_id.uom_id.id, r.product_id.standard_price, False)
|
||||
res ['value']['amount']= - round(amount, 2)
|
||||
res ['value']['general_account_id']= a
|
||||
return res
|
||||
|
||||
def on_change_user_id(self, cr, uid, ids,user_id, account_id, unit_amount=0):
|
||||
res = {}
|
||||
if not (user_id):
|
||||
#avoid a useless call to super
|
||||
return res
|
||||
|
||||
#get the old values from super
|
||||
res = super(hr_analytic_timesheet, self).on_change_user_id(cr, uid, ids,user_id)
|
||||
|
||||
if account_id:
|
||||
#get the browse record related to user_id and account_id
|
||||
# temp = self.pool.get('analytic_user_funct_grid').search(cr, uid, [('user_id', '=', user_id),('account_id', '=', account_id) ])
|
||||
temp = self._get_related_user_account_recursiv(cr,uid,user_id,account_id)
|
||||
if temp:
|
||||
#add the value from the new relation analytic_user_funct_grid
|
||||
r = self.pool.get('analytic_user_funct_grid').browse(cr, uid, temp)[0]
|
||||
res['value']['product_id'] = r.product_id.id
|
||||
|
||||
#the change of product has to impact the amount, uom and general_account_id
|
||||
a = r.product_id.product_tmpl_id.property_account_expense.id
|
||||
if not a:
|
||||
a = r.product_id.categ_id.property_account_expense_categ.id
|
||||
if not a:
|
||||
raise osv.except_osv('Error !',
|
||||
'There is no expense account define ' \
|
||||
'for this product: "%s" (id:%d)' % \
|
||||
(r.product_id.name, r.product_id.id,))
|
||||
amount = unit_amount * r.product_id.uom_id._compute_price(cr, uid,
|
||||
r.product_id.uom_id.id, r.product_id.standard_price, False)
|
||||
res ['value']['amount']= - round(amount, 2)
|
||||
res ['value']['general_account_id']= a
|
||||
return res
|
||||
|
||||
hr_analytic_timesheet()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- analytic_user_funct_grid views -->
|
||||
<record model="ir.ui.view" id="analytic_user_funct_grid_tree">
|
||||
<field name="name">analytic_user_funct_grid.tree</field>
|
||||
<field name="model">analytic_user_funct_grid</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="User's Product for this Analytic Account" editable="bottom">
|
||||
<field name="user_id" required="1"/>
|
||||
<field name="product_id" required="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="analytic_user_funct_grid_form">
|
||||
<field name="name">analytic_user_funct_grid.form</field>
|
||||
<field name="model">analytic_user_funct_grid</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="User's Product for this Analytic Account">
|
||||
<field name="user_id" required="1"/>
|
||||
<field name="product_id" required="1"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- account.analytic.account inherited view -->
|
||||
<record model="ir.ui.view" id="view_account_analytic_account_form_inherit">
|
||||
<field name="name">account.analytic.account.form</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="account.view_account_analytic_account_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/notebook/page" position="after">
|
||||
<page string="Users/Products Rel.">
|
||||
<field name="user_product_ids" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- hr_timesheet_sheet.sheet inherited view -->
|
||||
<record model="ir.ui.view" id="hr_timesheet_sheet_form_inherit">
|
||||
<field name="name">hr.timesheet.sheet.form</field>
|
||||
<field name="model">hr_timesheet_sheet.sheet</field>
|
||||
<field name="type">form</field>
|
||||
<field name="priority" eval="18"/>
|
||||
<field name="inherit_id" ref="hr_timesheet_sheet.hr_timesheet_sheet_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/notebook/page/field[@name='timesheet_ids']/tree/field[@name='account_id']" position="replace">
|
||||
<field name="account_id" domain="[('type','=','normal'),('state', '<>', 'close')]" on_change="on_change_account_id(user_id, account_id, unit_amount)"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- hr.analytic.timesheet inherited views -->
|
||||
<record model="ir.ui.view" id="hr_timesheet_line_form_inherit">
|
||||
<field name="name">hr.analytic.timesheet.form</field>
|
||||
<field name="model">hr.analytic.timesheet</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/field[@name='account_id']" position="replace">
|
||||
<field name="account_id" domain="[('type','=','normal'),('state', '<>', 'close')]" on_change="on_change_account_id(user_id, account_id, unit_amount)" select="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_timesheet_line_form_inherit_2">
|
||||
<field name="name">hr.analytic.timesheet.form</field>
|
||||
<field name="model">hr.analytic.timesheet</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/field[@name='user_id']" position="replace">
|
||||
<field name="user_id" select="1" required="1" on_change="on_change_user_id(user_id, account_id, unit_amount)"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_timesheet_line_tree_inherit">
|
||||
<field name="name">hr.analytic.timesheet.tree</field>
|
||||
<field name="model">hr.analytic.timesheet</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/tree/field[@name='account_id']" position="replace">
|
||||
<field name="account_id" domain="[('type','=','normal'),('state', '<>', 'close')]" on_change="on_change_account_id(user_id, account_id, unit_amount)" select="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_timesheet_line_tree_inherit_2">
|
||||
<field name="name">hr.analytic.timesheet.tree</field>
|
||||
<field name="model">hr.analytic.timesheet</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/tree/field[@name='user_id']" position="replace">
|
||||
<field name="user_id" select="1" required="1" on_change="on_change_user_id(user_id, account_id, unit_amount)"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,5 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
import audittrail
|
||||
import wizard
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
#
|
||||
# you must set the depends variable on modules you plan to audit !
|
||||
#
|
||||
{
|
||||
"name" : "Audit Trail",
|
||||
"version" : "1.0",
|
||||
"depends" : ["base","account","purchase","mrp"],
|
||||
"website" : "http://tinyerp.com",
|
||||
"author" : "Tiny",
|
||||
"init_xml" : [],
|
||||
"description": "Allows the administrator to track every user operations on all objects of the system.",
|
||||
"category" : "Generic Modules/Others",
|
||||
"update_xml" : ["audittrail_view.xml"],
|
||||
"demo_xml" : ["audittrail_demo.xml"],
|
||||
"active" : False,
|
||||
"installable": True
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
from osv import osv, fields
|
||||
import time, pooler, copy
|
||||
import ir
|
||||
class audittrail_rule(osv.osv):
|
||||
_name = 'audittrail.rule'
|
||||
_columns = {
|
||||
"name": fields.char("Rule Name", size=32, required=True),
|
||||
"object_id": fields.many2one('ir.model', 'Object', required=True),
|
||||
"user_id": fields.many2many('res.users', 'audittail_rules_users', 'user_id', 'rule_id', 'Users'),
|
||||
"log_read": fields.boolean("Log reads"),
|
||||
"log_write": fields.boolean("Log writes"),
|
||||
"log_unlink": fields.boolean("Log deletes"),
|
||||
"log_create": fields.boolean("Log creates"),
|
||||
"state": fields.selection((("draft", "Draft"),("subscribed", "Subscribed")), "State", required=True),
|
||||
"action_id":fields.many2one('ir.actions.act_window',"Action ID"),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'state': lambda *a: 'draft',
|
||||
'log_create': lambda *a: 1,
|
||||
'log_unlink': lambda *a: 1,
|
||||
'log_write': lambda *a: 1,
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('model_uniq', 'unique (object_id)', """There is a rule defined on this object\n You can not define other on the same!""")
|
||||
]
|
||||
__functions = {}
|
||||
|
||||
def __init__(self,pool,cr=None):
|
||||
for obj_name in pool.obj_list():
|
||||
obj=pool.get(obj_name)
|
||||
for field in ('read','write','create','unlink'):
|
||||
setattr(obj, field, self.logging_fct(getattr(obj,field), obj))
|
||||
super(audittrail_rule, self).__init__(pool,cr)
|
||||
|
||||
def subscribe(self, cr, uid, ids, *args):
|
||||
for thisrule in self.browse(cr, uid, ids):
|
||||
obj = self.pool.get(thisrule.object_id.model)
|
||||
if not obj:
|
||||
raise osv.except_osv(
|
||||
'WARNING:audittrail is not part of the pool',
|
||||
'Change audittrail depends -- Setting rule as DRAFT')
|
||||
self.write(cr, uid, [thisrule.id], {"state": "draft"})
|
||||
val={
|
||||
"name":'View Log',
|
||||
"res_model":'audittrail.log',
|
||||
"src_model":thisrule.object_id.model,
|
||||
"domain":"[('res_id', '=', active_id)]"
|
||||
|
||||
}
|
||||
id=self.pool.get('ir.actions.act_window').create(cr, uid, val)
|
||||
self.write(cr, uid, ids, {"state": "subscribed","action_id":id})
|
||||
keyword = 'client_action_relate'
|
||||
value = 'ir.actions.act_window,'+str(id)
|
||||
res=self.pool.get('ir.model.data').ir_set(cr, uid, 'action', keyword,'View_log_'+thisrule.object_id.model, [thisrule.object_id.model], value, replace=True, isobject=True, xml_id=False)
|
||||
return True
|
||||
|
||||
|
||||
def logging_fct(self, fct_src, obj):
|
||||
object_name=obj._name
|
||||
object=None
|
||||
logged_uids = []
|
||||
def get_value_text(cr, uid, field_name,values,object, context={}):
|
||||
f_id= self.pool.get('ir.model.fields').search(cr, uid,[('name','=',field_name),('model_id','=',object.id)])
|
||||
if f_id:
|
||||
field=self.pool.get('ir.model.fields').read(cr, uid,f_id)[0]
|
||||
model=field['relation']
|
||||
|
||||
if field['ttype']=='many2one':
|
||||
if values:
|
||||
if type(values)==tuple:
|
||||
values=values[0]
|
||||
val=self.pool.get(model).read(cr,uid,[values],['name'])
|
||||
if len(val):
|
||||
return val[0]['name']
|
||||
|
||||
elif field['ttype'] == 'many2many':
|
||||
value=[]
|
||||
if values:
|
||||
for id in values:
|
||||
val=self.pool.get(model).read(cr,uid,[id],['name'])
|
||||
if len(val):
|
||||
value.append(val[0]['name'])
|
||||
return value
|
||||
|
||||
elif field['ttype'] == 'one2many':
|
||||
|
||||
if values:
|
||||
value=[]
|
||||
for id in values:
|
||||
val=self.pool.get(model).read(cr,uid,[id],['name'])
|
||||
if len(val):
|
||||
value.append(val[0]['name'])
|
||||
return value
|
||||
return values
|
||||
|
||||
def create_log_line(cr,uid,id,object,lines=[]):
|
||||
for line in lines:
|
||||
f_id= self.pool.get('ir.model.fields').search(cr, uid,[('name','=',line['name']),('model_id','=',object.id)])
|
||||
if len(f_id):
|
||||
fields=self.pool.get('ir.model.fields').read(cr, uid,f_id)
|
||||
old_value='old_value' in line and line['old_value'] or ''
|
||||
new_value='new_value' in line and line['new_value'] or ''
|
||||
old_value_text='old_value_text' in line and line['old_value_text'] or ''
|
||||
new_value_text='new_value_text' in line and line['new_value_text'] or ''
|
||||
|
||||
if fields[0]['ttype']== 'many2one':
|
||||
if type(old_value)==tuple:
|
||||
old_value=old_value[0]
|
||||
if type(new_value)==tuple:
|
||||
new_value=new_value[0]
|
||||
self.pool.get('audittrail.log.line').create(cr, uid, {"log_id": id, "field_id": f_id[0] ,"old_value":old_value ,"new_value":new_value,"old_value_text":old_value_text ,"new_value_text":new_value_text,"field_description":fields[0]['field_description']})
|
||||
return True
|
||||
|
||||
def my_fct( cr, uid, *args, **args2):
|
||||
obj_ids= self.pool.get('ir.model').search(cr, uid,[('model','=',object_name)])
|
||||
if not len(obj_ids):
|
||||
return fct_src(cr, uid, *args, **args2)
|
||||
object=self.pool.get('ir.model').browse(cr,uid,obj_ids)[0]
|
||||
rule_ids=self.search(cr, uid, [('object_id','=',obj_ids[0]),('state','=','subscribed')])
|
||||
if not len(rule_ids):
|
||||
return fct_src(cr, uid, *args, **args2)
|
||||
|
||||
field=fct_src.__name__
|
||||
for thisrule in self.browse(cr, uid, rule_ids):
|
||||
if not getattr(thisrule, 'log_'+field):
|
||||
return fct_src(cr, uid, *args, **args2)
|
||||
self.__functions.setdefault(thisrule.id, [])
|
||||
self.__functions[thisrule.id].append( (obj,field, getattr(obj,field)) )
|
||||
for user in thisrule.user_id:
|
||||
logged_uids.append(user.id)
|
||||
|
||||
if fct_src.__name__ in ('create'):
|
||||
res_id =fct_src( cr, uid, *args, **args2)
|
||||
new_value=self.pool.get(object.model).read(cr,uid,[res_id],args[0].keys())[0]
|
||||
if 'id' in new_value:
|
||||
del new_value['id']
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
id=self.pool.get('audittrail.log').create(cr, uid, {"method": fct_src.__name__, "object_id": object.id, "user_id": uid, "res_id": res_id,"name": "%s %s %s" % (fct_src.__name__, object.id, time.strftime("%Y-%m-%d %H:%M:%S"))})
|
||||
lines=[]
|
||||
for field in new_value:
|
||||
if new_value[field]:
|
||||
line={
|
||||
'name':field,
|
||||
'new_value':new_value[field],
|
||||
'new_value_text':get_value_text(cr,uid,field,new_value[field],object)
|
||||
}
|
||||
lines.append(line)
|
||||
create_log_line(cr,uid,id,object,lines)
|
||||
return res_id
|
||||
|
||||
if fct_src.__name__ in ('write'):
|
||||
res_ids=args[0]
|
||||
for res_id in res_ids:
|
||||
old_values=self.pool.get(object.model).read(cr,uid,res_id,args[1].keys())
|
||||
old_values_text={}
|
||||
for field in args[1].keys():
|
||||
old_values_text[field]=get_value_text(cr,uid,field,old_values[field],object)
|
||||
res =fct_src( cr, uid, *args, **args2)
|
||||
if res:
|
||||
new_values=self.pool.get(object.model).read(cr,uid,res_ids,args[1].keys())[0]
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
id=self.pool.get('audittrail.log').create(cr, uid, {"method": fct_src.__name__, "object_id": object.id, "user_id": uid, "res_id": res_id,"name": "%s %s %s" % (fct_src.__name__, object.id, time.strftime("%Y-%m-%d %H:%M:%S"))})
|
||||
lines=[]
|
||||
for field in args[1].keys():
|
||||
if args[1].keys():
|
||||
line={
|
||||
'name':field,
|
||||
'new_value':field in new_values and new_values[field] or '',
|
||||
'old_value':field in old_values and old_values[field] or '',
|
||||
'new_value_text':get_value_text(cr,uid,field,new_values[field],object),
|
||||
'old_value_text':old_values_text[field]
|
||||
}
|
||||
lines.append(line)
|
||||
create_log_line(cr,uid,id,object,lines)
|
||||
return res
|
||||
|
||||
if fct_src.__name__ in ('read'):
|
||||
res_ids=args[0]
|
||||
old_values={}
|
||||
res =fct_src( cr, uid,*args, **args2)
|
||||
if type(res)==list:
|
||||
|
||||
for v in res:
|
||||
old_values[v['id']]=v
|
||||
else:
|
||||
|
||||
old_values[res['id']]=res
|
||||
for res_id in old_values:
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
id=self.pool.get('audittrail.log').create(cr, uid, {"method": fct_src.__name__, "object_id": object.id, "user_id": uid, "res_id": res_id,"name": "%s %s %s" % (fct_src.__name__, object.id, time.strftime("%Y-%m-%d %H:%M:%S"))})
|
||||
lines=[]
|
||||
for field in old_values[res_id]:
|
||||
if old_values[res_id][field]:
|
||||
line={
|
||||
'name':field,
|
||||
'old_value':old_values[res_id][field],
|
||||
'old_value_text':get_value_text(cr,uid,field,old_values[res_id][field],object)
|
||||
}
|
||||
lines.append(line)
|
||||
create_log_line(cr,uid,id,object,lines)
|
||||
return res
|
||||
if fct_src.__name__ in ('unlink'):
|
||||
res_ids=args[0]
|
||||
old_values={}
|
||||
for res_id in res_ids:
|
||||
old_values[res_id]=self.pool.get(object.model).read(cr,uid,res_id,[])
|
||||
|
||||
for res_id in res_ids:
|
||||
if not len(logged_uids) or uid in logged_uids:
|
||||
id=self.pool.get('audittrail.log').create(cr, uid, {"method": fct_src.__name__, "object_id": object.id, "user_id": uid, "res_id": res_id,"name": "%s %s %s" % (fct_src.__name__, object.id, time.strftime("%Y-%m-%d %H:%M:%S"))})
|
||||
lines=[]
|
||||
for field in old_values[res_id]:
|
||||
if old_values[res_id][field]:
|
||||
line={
|
||||
'name':field,
|
||||
'old_value':old_values[res_id][field],
|
||||
'old_value_text':get_value_text(cr,uid,field,old_values[res_id][field],object)
|
||||
}
|
||||
lines.append(line)
|
||||
create_log_line(cr,uid,id,object,lines)
|
||||
res =fct_src( cr, uid,*args, **args2)
|
||||
return res
|
||||
|
||||
return my_fct
|
||||
|
||||
def unsubscribe(self, cr, uid, ids, *args):
|
||||
for thisrule in self.browse(cr, uid, ids):
|
||||
if thisrule.id in self.__functions :
|
||||
for function in self.__functions[thisrule.id]:
|
||||
setattr(function[0], function[1], function[2])
|
||||
w_id=self.pool.get('ir.actions.act_window').search(cr, uid, [('name','=','View Log'),('res_model','=','audittrail.log'),('src_model','=',thisrule.object_id.model)])
|
||||
self.pool.get('ir.actions.act_window').unlink(cr, uid,w_id )
|
||||
val_obj=self.pool.get('ir.values')
|
||||
value="ir.actions.act_window"+','+str(w_id[0])
|
||||
val_id=val_obj.search(cr, uid, [('model','=',thisrule.object_id.model),('value','=',value)])
|
||||
if val_id:
|
||||
res = ir.ir_del(cr, uid, val_id[0])
|
||||
self.write(cr, uid, ids, {"state": "draft"})
|
||||
return True
|
||||
|
||||
audittrail_rule()
|
||||
|
||||
|
||||
class audittrail_log(osv.osv):
|
||||
_name = 'audittrail.log'
|
||||
_columns = {
|
||||
"name": fields.char("Name", size=32),
|
||||
"object_id": fields.many2one('ir.model', 'Object'),
|
||||
"user_id": fields.many2one('res.users', 'User'),
|
||||
"method": fields.selection((('read', 'Read'), ('write', 'Write'), ('unlink', 'Delete'), ('create', 'Create')), "Method"),
|
||||
"timestamp": fields.datetime("Date"),
|
||||
"res_id":fields.integer('Resource Id'),
|
||||
"line_ids":fields.one2many('audittrail.log.line','log_id','Log lines')
|
||||
|
||||
}
|
||||
_defaults = {
|
||||
"timestamp": lambda *a: time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
}
|
||||
|
||||
audittrail_log()
|
||||
|
||||
class audittrail_log_line(osv.osv):
|
||||
_name='audittrail.log.line'
|
||||
_columns={
|
||||
'field_id': fields.many2one('ir.model.fields','Fields', required=True),
|
||||
'log_id':fields.many2one('audittrail.log','Log'),
|
||||
'log':fields.integer("Log ID"),
|
||||
'old_value':fields.text("Old Value"),
|
||||
'new_value':fields.text("New Value"),
|
||||
'old_value_text':fields.text('Old value Text' ),
|
||||
'new_value_text':fields.text('New value Text' ),
|
||||
'field_description':fields.char('Field Description' ,size=64),
|
||||
}
|
||||
|
||||
audittrail_log_line()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record model="audittrail.rule" id="demo_audittrail_rule">
|
||||
<field name="name">Audit on Partners</field>
|
||||
<field name="object_id" search="[('model','=','res.partner')]"/>
|
||||
<field name="user_id" search="[]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="view_audittrail_rule_form">
|
||||
<field name="name">audittrail.rule.form</field>
|
||||
<field name="model">audittrail.rule</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="AuditTrail Rule">
|
||||
<field name="name" select="1" required="1"/>
|
||||
<field name="object_id" select="1"/>
|
||||
<field name="log_read" />
|
||||
<field name="log_write" />
|
||||
<field name="log_unlink" />
|
||||
<field name="log_create" />
|
||||
<field name="action_id" colspan="4" readonly="1"/>
|
||||
<field name="user_id" select="1" colspan="4"/>
|
||||
<field name="state" select="1" readonly="1" />
|
||||
<group colspan="2" col="2">
|
||||
<button string="Subscribe" name="subscribe" type="object" states="draft"/>
|
||||
<button string="UnSubscribe" name="unsubscribe" type="object" states="subscribed"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_audittrail_rule_tree">
|
||||
<field name="name">audittrail.rule.tree</field>
|
||||
<field name="model">audittrail.rule</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="AuditTrail Rules">
|
||||
<field name="name" />
|
||||
<field name="object_id"/>
|
||||
<field name="user_id" />
|
||||
<field name="log_read" />
|
||||
<field name="log_write" />
|
||||
<field name="log_unlink" />
|
||||
<field name="log_create" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.act_window" id="action_audittrail_rule_tree">
|
||||
<field name="res_model">audittrail.rule</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<!--<field name="view_id" ref="view_audittrail_rule_form" />-->
|
||||
</record>
|
||||
<menuitem name="Audittrails" id="menu_action_audittrail" parent="base.menu_administration"/>
|
||||
<menuitem name="Rules" id="menu_action_audittrail_rule_tree" action="action_audittrail_rule_tree" parent="menu_action_audittrail"/>
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_audittrail_rule_tree_sub">
|
||||
<field name="res_model">audittrail.rule</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state','=','subscribed')]</field>
|
||||
</record>
|
||||
<menuitem name="Subscribed Rules" id="menu_action_audittrail_rule_tree_sub" action="action_audittrail_rule_tree_sub" parent="menu_action_audittrail_rule_tree"/>
|
||||
|
||||
<record model="ir.ui.view" id="view_audittrail_log_form">
|
||||
<field name="name">audittrail.log.form</field>
|
||||
<field name="model">audittrail.log</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="AuditTrail Logs">
|
||||
<field name="timestamp" select="1" required="1" readonly="1"/>
|
||||
<field name="object_id" select="1" readonly="1"/>
|
||||
<field name="method" select="1" readonly="1"/>
|
||||
<field name="user_id" select="1" readonly="1"/>
|
||||
<field name="res_id" readonly="1" colspan="4"/>
|
||||
<field name="line_ids" colspan="4" mode="tree,form" widget="one2many_list" readonly="1">
|
||||
<form string="Log Lines">
|
||||
<field name="field_id" colspan="4" readonly="1"/>
|
||||
<newline/>
|
||||
<field name="field_description" colspan="4" readonly="1"/>
|
||||
<newline/>
|
||||
<separator string="Old Value : " colspan="2" readonly="1"/>
|
||||
<separator string="New Value : " colspan="2" readonly="1"/>
|
||||
<newline/>
|
||||
<field name="old_value" nolabel="1" colspan="2" readonly="1"/>
|
||||
<field name="new_value" nolabel="1" colspan="2" readonly="1"/>
|
||||
<newline/>
|
||||
<separator string="Old Value Text : " colspan="2" readonly="1"/>
|
||||
<separator string="New Value Text: " colspan="2" readonly="1"/>
|
||||
<newline/>
|
||||
<field name="old_value_text" nolabel="1" colspan="2" readonly="1"/>
|
||||
<field name="new_value_text" nolabel="1" colspan="2" readonly="1"/>
|
||||
</form>
|
||||
|
||||
<tree string="Log Lines">
|
||||
<field name="field_description" />
|
||||
<field name="old_value_text" />
|
||||
<field name="new_value_text" />
|
||||
</tree>
|
||||
</field>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_audittrail_log_tree">
|
||||
<field name="name">audittrail.log.tree</field>
|
||||
<field name="model">audittrail.log</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="AuditTrail Logs">
|
||||
<field name="timestamp" />
|
||||
<field name="object_id" />
|
||||
<field name="method" />
|
||||
<field name="user_id" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_audittrail_log_tree">
|
||||
<field name="res_model">audittrail.log</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
<menuitem name="Logs" id="menu_action_audittrail_log_tree" action="action_audittrail_log_tree" parent="menu_action_audittrail"/>
|
||||
|
||||
<wizard string="View log" menu="False" model="audittrail.log" name="audittrail.view.log" id="wizard_audittrail_log"/>
|
||||
<menuitem name="View Logs" id="menu_action_log_tree2" action="wizard_audittrail_log" type="wizard" parent="menu_action_audittrail"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,4 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
import wizard_view_log
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
import wizard
|
||||
import pooler
|
||||
import time
|
||||
|
||||
class wizard_view_log(wizard.interface):
|
||||
|
||||
form1 = '''<?xml version="1.0"?>
|
||||
<form string="Audit Logs">
|
||||
<field name="from" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="to" colspan="4"/>
|
||||
</form>'''
|
||||
|
||||
form1_fields = {
|
||||
'from': {
|
||||
'string': 'Log From',
|
||||
'type': 'datetime',
|
||||
|
||||
},
|
||||
'to': {
|
||||
'string': 'Log To',
|
||||
'type': 'datetime',
|
||||
'default': lambda *a: time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
'required':True
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _log_open_window(self, cr, uid, data, context):
|
||||
mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
|
||||
act_obj = pooler.get_pool(cr.dbname).get('ir.actions.act_window')
|
||||
result = mod_obj._get_id(cr, uid, 'audittrail', 'action_audittrail_log_tree')
|
||||
id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
|
||||
result = act_obj.read(cr, uid, [id])[0]
|
||||
log_obj= pooler.get_pool(cr.dbname).get(result['res_model'])
|
||||
log_id = log_obj.search(cr, uid, [])
|
||||
log_model=log_obj.read(cr, uid,log_id,['object_id'])
|
||||
if not data['form']['from']:
|
||||
if data['form']['to'] <> time.strftime("%Y-%m-%d %H:%M:%S"):
|
||||
result['domain'] = str([('timestamp', '<',data['form']['to'])])
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
result['domain'] = str([('timestamp', '>',data['form']['from']),('timestamp', '<',data['form']['to'])])
|
||||
|
||||
return result
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':form1, 'fields':form1_fields, 'state': [('end', 'Cancel'), ('open', 'Open Logs')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action':_log_open_window, 'state':'end'}
|
||||
}
|
||||
}
|
||||
wizard_view_log('audittrail.view.log')
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
"mrp_view.xml",
|
||||
"mrp_wizard.xml",
|
||||
"mrp_report.xml",
|
||||
"company_view.xml"
|
||||
"company_view.xml",
|
||||
],
|
||||
"active": False,
|
||||
"installable": True
|
||||
|
|
|
@ -29,6 +29,13 @@
|
|||
<field eval="'ir.actions.wizard,%d'%wizard_price" name="value"/>
|
||||
<field eval="True" name="object"/>
|
||||
</record>
|
||||
|
||||
|
||||
<wizard
|
||||
string="Create Procurement"
|
||||
model="product.product"
|
||||
name="product.product.procurement"
|
||||
keyword="client_action_multi"
|
||||
id="product_procurement_wizard"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -34,6 +34,7 @@ import wizard_schedulers_all
|
|||
import wizard_price
|
||||
import wizard_workcenter_load
|
||||
import wizard_track_prod
|
||||
import make_procurement
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2007 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
import netsvc
|
||||
|
||||
import time
|
||||
|
||||
def _get_default(obj, cr, uid, data, context=None):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
product = pool.get('product.product').browse(cr, uid, data['id'], context)
|
||||
return {'product_id': product.id, 'uom_id':product.uom_id.id, 'qty':1.0}
|
||||
|
||||
def make_procurement(obj, cr, uid, data, context=None):
|
||||
'''Create procurement'''
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
wh = pool.get('stock.warehouse').browse(cr, uid, data['form']['warehouse_id'], context)
|
||||
user = pool.get('res.users').browse(cr, uid, uid, context)
|
||||
procure_id = pool.get('mrp.procurement').create(cr, uid, {
|
||||
'name':'INT:'+str(user.login),
|
||||
'date_planned':data['form']['date_planned'],
|
||||
'product_id':data['form']['product_id'],
|
||||
'product_qty':data['form']['qty'],
|
||||
'product_uom':data['form']['uom_id'],
|
||||
'location_id':wh.lot_stock_id.id,
|
||||
'procure_method':'make_to_order',
|
||||
}, context=context)
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
wf_service.trg_validate(uid, 'mrp.procurement', procure_id, 'button_confirm', cr)
|
||||
return {}
|
||||
|
||||
|
||||
class MakeProcurement(wizard.interface):
|
||||
'''Wizard that create a procurement from a product form'''
|
||||
|
||||
done_form = """<?xml version="1.0"?>
|
||||
<form string="Make Procurement">
|
||||
<label string="Your procurement request has been sent !"/>
|
||||
</form>"""
|
||||
procurement_form = """<?xml version="1.0"?>
|
||||
<form string="Make Procurement">
|
||||
<field name="product_id"/>
|
||||
<field name="warehouse_id"/>
|
||||
<field name="qty"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="date_planned"/>
|
||||
</form>"""
|
||||
procurement_fields = {
|
||||
'qty': {'string': 'Quantity', 'type': 'float', 'digits':(16,2), 'required': True},
|
||||
'product_id': {'string': 'product', 'type': 'many2one', 'relation': 'product.product', 'required': True, 'readonly':1},
|
||||
'uom_id': {'string': 'Unit of Measure', 'type': 'many2one', 'relation': 'product.uom', 'required':True},
|
||||
'warehouse_id': {'string': 'Location', 'type': 'many2one', 'relation':'stock.warehouse', 'required':True},
|
||||
'date_planned': {'string': 'Planned Date', 'type': 'date', 'required':True, 'default': lambda *args: time.strftime('%Y-%m-%d')}
|
||||
}
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [_get_default],
|
||||
'result': {'type': 'form', 'arch': procurement_form, 'fields': procurement_fields,
|
||||
'state': [
|
||||
('end', 'Cancel'),
|
||||
('create', 'Ask New Products')
|
||||
]
|
||||
}
|
||||
},
|
||||
'done': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch': done_form, 'fields': {},
|
||||
'state': [
|
||||
('end', 'Close'),
|
||||
]
|
||||
}
|
||||
},
|
||||
'create': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action': make_procurement, 'state': 'done'}
|
||||
}
|
||||
}
|
||||
|
||||
MakeProcurement('product.product.procurement')
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -30,6 +30,7 @@ import product
|
|||
import pricelist
|
||||
import report
|
||||
import partner
|
||||
import wizard
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
"security/ir.model.access.csv",
|
||||
"product_data.xml","product_report.xml",
|
||||
"product_view.xml", "pricelist_view.xml",
|
||||
"partner_view.xml"],
|
||||
"partner_view.xml", "product_wizard.xml"],
|
||||
"active": False,
|
||||
"installable": True
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
<wizard
|
||||
id="report_wizard_price"
|
||||
string="Price List"
|
||||
model="product.product"
|
||||
name="product.price_list"
|
||||
keyword="client_print_multi"/>
|
||||
</data>
|
||||
</openerp>
|
|
@ -27,7 +27,7 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import product_pricelist
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
#
|
||||
# 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 datetime
|
||||
from report.interface import report_rml
|
||||
from report.interface import toxml
|
||||
import pooler
|
||||
from osv import osv
|
||||
import datetime
|
||||
|
||||
class report_custom(report_rml):
|
||||
|
||||
def create_xml(self, cr, uid, ids, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
|
||||
price_list_id = data['form']['price_list']
|
||||
|
||||
product_categ_id =pool.get('product.category').search(cr,uid,[])
|
||||
currency = pool.get('product.pricelist').read(cr,uid,[price_list_id],['currency_id','name'])[0]
|
||||
|
||||
|
||||
qty =[]
|
||||
|
||||
for i in range(1,6):
|
||||
q = 'qty%d'%i
|
||||
if data['form'][q]:
|
||||
qty.append(data['form'][q])
|
||||
|
||||
if not qty:
|
||||
qty.append(1)
|
||||
|
||||
product_xml = []
|
||||
cols = ''
|
||||
cols = cols+'6cm'
|
||||
title ='<title name=" Description " number="0" />'
|
||||
i=1
|
||||
for q in qty:
|
||||
cols = cols+',2.5cm'
|
||||
if q==1:
|
||||
title+='<title name="%d unit" number="%d"/>'%(q,i)
|
||||
else:
|
||||
title+='<title name="%d units" number="%d"/>'%(q,i)
|
||||
i+=1
|
||||
date = datetime.date.today()
|
||||
str_date=date.strftime("%d/%m/%Y")
|
||||
product_xml.append('<cols>'+cols+'</cols>')
|
||||
product_xml.append('<pricelist> %s </pricelist>'%currency['name'])
|
||||
product_xml.append('<currency> %s </currency>'%currency['currency_id'][1])
|
||||
product_xml.append('<date> %s </date>'%str_date)
|
||||
product_xml.append("<product>")
|
||||
|
||||
for p_categ_id in product_categ_id:
|
||||
product_ids = pool.get('product.product').search(cr,uid,[('id','in',ids),('categ_id','=',p_categ_id)])
|
||||
if product_ids:
|
||||
categ_name = pool.get('product.category').read(cr,uid,[p_categ_id],['name'])
|
||||
products = pool.get('product.product').read(cr,uid,product_ids,['id','name','code'])
|
||||
pro = []
|
||||
i=0
|
||||
pro.append('<pro name="%s" categ="true">' % (categ_name[0]['name']))
|
||||
temp = []
|
||||
for q in qty:
|
||||
temp.append('<price name=" " />')
|
||||
pro.extend(temp)
|
||||
pro.append('</pro>')
|
||||
for x in products:
|
||||
#Replacement of special characters with their code html for allowing reporting - Edited by Hasa
|
||||
x['name'] = x['name'].replace("&","&")
|
||||
x['name'] = x['name'].replace("\"",""")
|
||||
if x['code']:
|
||||
pro.append('<pro name="[%s] %s" >' % (x['code'], x['name']))
|
||||
else:
|
||||
pro.append('<pro name="%s" >' % (x['name']))
|
||||
temp = []
|
||||
for q in qty:
|
||||
price_dict = pool.get('product.pricelist').price_get(cr,uid,[price_list_id],x['id'],q)
|
||||
if price_dict[price_list_id]:
|
||||
price = price_dict[price_list_id]
|
||||
else:
|
||||
res = pool.get('product.product').read(cr, uid,[x['id']])
|
||||
price = res[0]['list_price']
|
||||
# temp.append('<price name="%s %s" />'%(price_list[i][x['id']]*q[2]['name'],currency['currency_id'][1]))
|
||||
|
||||
temp.append('<price name="%.2f" />'%(price))
|
||||
i+=1
|
||||
pro.extend(temp)
|
||||
pro.append('</pro>')
|
||||
# categ.extend(pro)
|
||||
# categ.append('</categ>')
|
||||
product_xml.extend(pro)
|
||||
|
||||
product_xml.append('</product>')
|
||||
|
||||
xml = '''<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<report>
|
||||
%s
|
||||
</report>
|
||||
''' % (title+'\n'.join(product_xml))
|
||||
return self.post_process_xml_data(cr, uid, xml, context)
|
||||
|
||||
report_custom('report.pricelist.pricelist', 'product.product','','addons/product_pricelist_print/report/product_price.xsl')
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format">
|
||||
<xsl:import href="../../custom/corporate_defaults.xsl" />
|
||||
<xsl:template match="/">
|
||||
<xsl:call-template name="rml" />
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template name="rml" match="/">
|
||||
<document filename="example.pdf">
|
||||
<template>
|
||||
<pageTemplate id="first">
|
||||
<frame id="first" x1="1cm" y1="2.5cm" width="19.0cm" height="23.0cm"/>
|
||||
<pageGraphics>
|
||||
<xsl:apply-imports />
|
||||
</pageGraphics>
|
||||
</pageTemplate>
|
||||
</template>
|
||||
<stylesheet>
|
||||
<paraStyle name="normal" fontName="Times-Roman" fontSize="12" />
|
||||
<paraStyle name="title" fontName="Times-Bold" fontSize="15" alignment="center" />
|
||||
<paraStyle name="table_title" fontName="Times-Bold" fontSize="12" alignment="center" />
|
||||
<paraStyle name="product1" fontName="Times-Roman" fontSize="8" />
|
||||
<paraStyle name="categ" fontName="Times-Bold" fontSize="10" textColor="blue"/>
|
||||
<paraStyle name="price" fontName="Times-Roman" fontSize="8" alignment="right" />
|
||||
|
||||
<blockTableStyle id="main_title">
|
||||
<blockAlignment value="CENTER" />
|
||||
<lineStyle kind="GRID" colorName="black"/>
|
||||
<blockBackground colorName="#e6e6e6" />
|
||||
<blockValign value="TOP"/>
|
||||
</blockTableStyle>
|
||||
|
||||
<blockTableStyle id="product">
|
||||
<blockAlignment value="LEFT" />
|
||||
<xsl:for-each select="/report/title">
|
||||
<xsl:variable name="col" select="attribute::number" />
|
||||
<blockBackground>
|
||||
<xsl:attribute name="colorName">#e6e6e6</xsl:attribute>
|
||||
<xsl:attribute name="start">
|
||||
<xsl:value-of select="$col" />
|
||||
<xsl:text>,0</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="stop">
|
||||
<xsl:value-of select="$col" />
|
||||
<xsl:text>,0</xsl:text>
|
||||
</xsl:attribute>
|
||||
</blockBackground>
|
||||
</xsl:for-each>
|
||||
<lineStyle kind="LINEABOVE" colorName="black" start="0,0" stop="-1,-1" />
|
||||
<lineStyle kind="LINEBEFORE" colorName="black" start="0,0" stop="-1,-1"/>
|
||||
<lineStyle kind="LINEAFTER" colorName="black" start="-1,0" stop="-1,-1"/>
|
||||
<lineStyle kind="LINEBELOW" colorName="black" start="0,-1" stop="-1,-1"/>
|
||||
<blockValign value="TOP"/>
|
||||
</blockTableStyle>
|
||||
</stylesheet >
|
||||
<story>
|
||||
<xsl:call-template name="story"/>
|
||||
</story>
|
||||
</document>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="story">
|
||||
<spacer length="1cm" />
|
||||
<blockTable rowHeights="1cm">
|
||||
<xsl:attribute name="style">main_title</xsl:attribute>
|
||||
<tr> <td> <para style="title" t="1">Products Price List</para> </td> </tr>
|
||||
</blockTable>
|
||||
<spacer length="1cm" />
|
||||
<para style="normal" t="1">Price List Name :<xsl:value-of select="report/pricelist" /></para>
|
||||
<para style="normal" t="1">Currency : <xsl:value-of select="report/currency" /></para>
|
||||
<para style="normal" t="1">Printing Date : <xsl:value-of select="report/date" /></para>
|
||||
<spacer length="0.7cm" />
|
||||
<blockTable>
|
||||
<xsl:attribute name="style">product</xsl:attribute>
|
||||
<xsl:attribute name="colWidths"><xsl:value-of select="report/cols" /></xsl:attribute>
|
||||
<tr>
|
||||
<xsl:for-each select="report/title" >
|
||||
<td><para style="table_title"> <xsl:value-of select="attribute::name" /> </para></td>
|
||||
</xsl:for-each>
|
||||
</tr>
|
||||
|
||||
<xsl:for-each select="report/product/pro" >
|
||||
<tr>
|
||||
<xsl:choose>
|
||||
<xsl:when test="@categ">
|
||||
<td> <para style="categ"><xsl:value-of select="attribute::name" /> </para> </td>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<td> <para style="product1"> <xsl:value-of select="attribute::name" /> </para> </td>
|
||||
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:for-each select="price" >
|
||||
<td><para style="price"> <xsl:value-of select="attribute::name" /> </para> </td>
|
||||
</xsl:for-each>
|
||||
</tr>
|
||||
</xsl:for-each>
|
||||
</blockTable>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,156 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
#
|
||||
# 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 time
|
||||
from report import report_sxw
|
||||
from osv import osv
|
||||
import pooler
|
||||
parents = {
|
||||
'tr':1,
|
||||
'li':1,
|
||||
'story': 0,
|
||||
'section': 0
|
||||
}
|
||||
class product_pricelist(report_sxw.rml_parse):
|
||||
def __init__(self, cr, uid, name, context):
|
||||
super(product_pricelist, self).__init__(cr, uid, name, context)
|
||||
self.pricelist=False
|
||||
self.quantity=[]
|
||||
self.localcontext.update({
|
||||
'time': time,
|
||||
'get_pricelist': self._get_pricelist,
|
||||
'get_currency': self._get_currency,
|
||||
'get_categories': self._get_categories,
|
||||
'get_price': self._get_price,
|
||||
'get_quantity':self._get_quantity,
|
||||
'qty_header':self._qty_header,
|
||||
})
|
||||
def _qty_header(self,form):
|
||||
qty=[]
|
||||
self.pricelist=form['price_list']
|
||||
for i in range(1,6):
|
||||
q = 'qty%d'%i
|
||||
if form[q]:
|
||||
self.quantity.append(form[q])
|
||||
if form[q]==1:
|
||||
qty.append('%d unit'%(form[q]))
|
||||
else:
|
||||
qty.append('%d units'%(form[q]))
|
||||
return qty
|
||||
|
||||
|
||||
def _get_quantity(self,form):
|
||||
qty=[]
|
||||
for i in range(1,6):
|
||||
q = 'qty%d'%i
|
||||
if form[q]:
|
||||
qty.append(form[q])
|
||||
return qty
|
||||
def _get_pricelist(self, pricelist_id):
|
||||
pool = pooler.get_pool(self.cr.dbname)
|
||||
pricelist = pool.get('product.pricelist').read(self.cr,self.uid,[pricelist_id],['name'])[0]
|
||||
return pricelist['name']
|
||||
def _get_currency(self, pricelist_id):
|
||||
pool = pooler.get_pool(self.cr.dbname)
|
||||
pricelist = pool.get('product.pricelist').read(self.cr,self.uid,[pricelist_id],['currency_id'])[0]
|
||||
return pricelist['currency_id'][1]
|
||||
def _get_categories(self, products):
|
||||
cat_ids=[]
|
||||
res=[]
|
||||
pool = pooler.get_pool(self.cr.dbname)
|
||||
pro_ids=[]
|
||||
for product in products:
|
||||
pro_ids.append(product.id)
|
||||
if product.categ_id.id not in cat_ids:
|
||||
cat_ids.append(product.categ_id.id)
|
||||
cats=pool.get('product.category').browse(self.cr,self.uid,cat_ids)
|
||||
for cat in cats:
|
||||
product_ids=pool.get('product.product').search(self.cr,self.uid,[('id','in',pro_ids),('categ_id','=',cat.id)])
|
||||
products = []
|
||||
for product in pool.get('product.product').browse(self.cr,self.uid,product_ids):
|
||||
val={
|
||||
'id':product.id,
|
||||
'name':product.name,
|
||||
'code':product.code
|
||||
}
|
||||
for qty in self.quantity:
|
||||
val[str(qty)]=self._get_price(self.pricelist,product.id,qty)
|
||||
products.append(val)
|
||||
|
||||
res.append({'name':cat.name,'products':products})
|
||||
return res
|
||||
|
||||
def _get_price(self,pricelist_id, product_id,qty):
|
||||
pool = pooler.get_pool(self.cr.dbname)
|
||||
price_dict = pool.get('product.pricelist').price_get(self.cr,self.uid,[pricelist_id],product_id,qty)
|
||||
if price_dict[pricelist_id]:
|
||||
price = self.formatLang(price_dict[pricelist_id])
|
||||
else:
|
||||
res = pool.get('product.product').read(self.cr, self.uid,[product_id])
|
||||
price = self.formatLang(res[0]['list_price'])
|
||||
return price
|
||||
|
||||
def repeatIn(self, lst, name, nodes_parent=False,value=[],width=False,type=False):
|
||||
self._node.data = ''
|
||||
node = self._find_parent(self._node, nodes_parent or parents)
|
||||
ns = node.nextSibling
|
||||
if not lst:
|
||||
lst.append(1)
|
||||
for ns in node.childNodes :
|
||||
if ns and ns.nodeName!='#text' and ns.tagName=='blockTable' and len(value) :
|
||||
width_str = ns._attrs['colWidths'].nodeValue
|
||||
ns.removeAttribute('colWidths')
|
||||
if not width or width=='':
|
||||
width=30
|
||||
if type.lower() in ('title'):
|
||||
width=width*len(value)
|
||||
width_str= '%d'%(float(width_str)+width)
|
||||
ns.setAttribute('colWidths',width_str)
|
||||
else:
|
||||
for v in value:
|
||||
width_str +=',%d'%width
|
||||
|
||||
ns.setAttribute('colWidths',width_str)
|
||||
child_list = ns.childNodes
|
||||
for child in child_list:
|
||||
if child.nodeName=='tr':
|
||||
lc = child.childNodes[1]
|
||||
t=0
|
||||
for v in value:
|
||||
newnode = lc.cloneNode(1)
|
||||
if type.lower() in ('string'):
|
||||
newnode.childNodes[1].lastChild.data="[[ %s['%s'] ]]"%(name,v)
|
||||
elif type.lower() in ('label'):
|
||||
newnode.childNodes[1].lastChild.data= "%s"%(v)
|
||||
child.appendChild(newnode)
|
||||
newnode=False
|
||||
return super(product_pricelist,self).repeatIn(lst, name, nodes_parent=False)
|
||||
#end
|
||||
report_sxw.report_sxw('report.product.pricelist','product.product','addons/product_pricelist_print/report/product_pricelist.rml',parser=product_pricelist)
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0"?>
|
||||
<document filename="test.pdf">
|
||||
<template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20">
|
||||
<pageTemplate id="first">
|
||||
<frame id="first" x1="57.0" y1="57.0" width="481" height="728"/>
|
||||
</pageTemplate>
|
||||
</template>
|
||||
<stylesheet>
|
||||
<blockTableStyle id="Standard_Outline">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
</blockTableStyle>
|
||||
<blockTableStyle id="Table1">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
<blockBackground colorName="#e6e6e6" start="0,0" stop="0,0"/>
|
||||
<lineStyle kind="GRID" colorName="black"/>
|
||||
</blockTableStyle>
|
||||
<blockTableStyle id="Table6">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
<blockBackground colorName="#e6e6e6" />
|
||||
<lineStyle kind="GRID" colorName="black"/>
|
||||
</blockTableStyle>
|
||||
<blockTableStyle id="Table3">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
<lineStyle kind="GRID" colorName="black"/>
|
||||
</blockTableStyle>
|
||||
<initialize>
|
||||
<paraStyle name="all" alignment="justify"/>
|
||||
</initialize>
|
||||
<paraStyle name="P1" fontName="Times-Roman" fontSize="9.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P2" fontName="Times-Roman" fontSize="9.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P3" fontName="Times-Roman" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P4" fontName="Times-Roman" alignment="CENTER"/>
|
||||
<paraStyle name="P5" fontName="Times-Roman" fontSize="8.0" leading="10"/>
|
||||
<paraStyle name="P6" fontName="Times-Bold" fontSize="11.0" leading="14" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P7" fontName="Times-Roman" alignment="LEFT"/>
|
||||
<paraStyle name="P8" fontName="Times-Roman" fontSize="20.0" leading="25" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P9" fontName="Times-Roman" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P10" fontName="Times-Roman" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P11" fontName="Times-Roman" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="P12" fontName="Times-Roman" fontSize="11.0" leading="14" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Standard" fontName="Times-Roman" fontSize="12"/>
|
||||
<paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="List" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Table Contents" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Table Heading" fontName="Times-Roman" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Caption" fontName="Times-Roman" fontSize="10.0" leading="13" spaceBefore="6.0" spaceAfter="6.0"/>
|
||||
<paraStyle name="Index" fontName="Times-Roman"/>
|
||||
<paraStyle name="cat" fontName="Times-Bold" textColor="blue" fontSize="10.0" leading="13" spaceBefore="6.0" spaceAfter="6.0"/>
|
||||
</stylesheet>
|
||||
<story>
|
||||
<para style="P5">
|
||||
<font color="white"> </font>
|
||||
</para>
|
||||
<blockTable colWidths="530.0" repeatRows="1" style="Table1">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="P8">Products Price List</para>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</blockTable>
|
||||
<para style="P5">
|
||||
<font color="white"> </font>
|
||||
</para>
|
||||
<para style="Standard">
|
||||
<font color="white"> </font>
|
||||
</para>
|
||||
<para style="Standard">Price List Name : [[ get_pricelist (data['form']['price_list']) ]]</para>
|
||||
<para style="Standard">Currency : [[ get_currency ( data['form']['price_list']) ]]</para>
|
||||
<para style="Standard">Printing Date: [[ formatLang(time.strftime('%Y-%m-%d'), date=True) ]]</para>
|
||||
<para style="P7">
|
||||
<font color="white"> </font>
|
||||
</para>
|
||||
<section>
|
||||
<para style="P6">[[repeatIn([],'qty_header',width=59,value=qty_header(data['form']),type='label') ]]</para>
|
||||
<blockTable colWidths="227.0" style="Table6">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="P6">Description</para>
|
||||
</td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
</section>
|
||||
<section>
|
||||
<para style="Standard">[[ repeatIn(get_categories(objects), 'c',width=59,value=get_quantity(data['form']),type='title') ]]</para>
|
||||
<blockTable colWidths="227.0" style="Table3">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="cat">[[ c['name'] ]]</para>
|
||||
</td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
|
||||
<section>
|
||||
<para style="Standard">[[repeatIn(c['products'], 'p',width=59,value=get_quantity(data['form']),type='string') ]]</para>
|
||||
<blockTable colWidths="227.0" style="Table3">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="P1">[[ p['code'] and '[' + p['code'] + '] ' or '' ]] [[ p['name'] ]]</para>
|
||||
</td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
</section>
|
||||
</section>
|
||||
<para style="P5"/>
|
||||
<para style="P3">
|
||||
<font color="white"> </font>
|
||||
</para>
|
||||
</story>
|
||||
</document>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
# Fabien Pinckaers <fp@tiny.Be>
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract a Free Software
|
||||
# Service Company
|
||||
#
|
||||
# This program is Free Software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
##############################################################################
|
||||
import wizard_price
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005-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 wizard
|
||||
|
||||
qty1_form = '''<?xml version="1.0"?>
|
||||
<form string="Price list">
|
||||
<field name="price_list" />
|
||||
<field name="qty1" colspan="2" />
|
||||
<field name="qty2" colspan="2" />
|
||||
<field name="qty3" colspan="2" />
|
||||
<field name="qty4" colspan="2" />
|
||||
<field name="qty5" colspan="2" />
|
||||
|
||||
</form>'''
|
||||
qty1_fields = {
|
||||
'price_list' : {'string' : 'PriceList', 'type' : 'many2one', 'relation' : 'product.pricelist', 'required':True },
|
||||
'qty1': {'string':'Quantity-1', 'type':'integer', 'default':0},
|
||||
'qty2': {'string':'Quantity-2', 'type':'integer', 'default':0},
|
||||
'qty3': {'string':'Quantity-3', 'type':'integer', 'default':0},
|
||||
'qty4': {'string':'Quantity-4', 'type':'integer', 'default':0},
|
||||
'qty5': {'string':'Quantity-5', 'type':'integer', 'default':0},
|
||||
}
|
||||
|
||||
|
||||
class wizard_qty(wizard.interface):
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type':'form', 'arch':qty1_form, 'fields':qty1_fields, 'state':[('end','Cancel'),('price','Print')]}
|
||||
},
|
||||
'price': {
|
||||
'actions': [],
|
||||
'result': {'type':'print', 'report':'product.pricelist', 'state':'end'}
|
||||
}
|
||||
|
||||
}
|
||||
wizard_qty('product.price_list')
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -18,6 +18,21 @@
|
|||
|
||||
<wizard id="wizard_invoice_onshipping" keyword="client_action_multi" model="stock.picking" name="stock.invoice_onshipping" string="Create invoice"/>
|
||||
|
||||
|
||||
<wizard
|
||||
string="Set Stock to 0"
|
||||
model="stock.inventory"
|
||||
name="inventory.merge.stock.zero"
|
||||
keyword="client_action_multi"
|
||||
id="wizard_merge_inventory_zero"/>
|
||||
|
||||
|
||||
<wizard
|
||||
string="Merge inventories"
|
||||
model="stock.inventory"
|
||||
name="inventory.merge"
|
||||
keyword="client_action_multi"
|
||||
multi="True"
|
||||
id="wizard_merge_inventory"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -37,6 +37,8 @@ import wizard_split_lot_line
|
|||
import wizard_track_line
|
||||
import wizard_ups
|
||||
import wizard_invoice_onshipping
|
||||
import inventory_merge
|
||||
import inventory_merge_zero
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
|
||||
|
||||
_form = """<?xml version="1.0"?>
|
||||
<form string="Merge inventories">
|
||||
<separator colspan="4" string="Merge inventories" />
|
||||
<label string="Do you want to merge theses inventories ?"/>
|
||||
</form>
|
||||
"""
|
||||
|
||||
|
||||
def do_merge(self, cr, uid, data, context):
|
||||
|
||||
invent_obj = pooler.get_pool(cr.dbname).get('stock.inventory')
|
||||
invent_line_obj = pooler.get_pool(cr.dbname).get('stock.inventory.line')
|
||||
|
||||
invent_lines = {}
|
||||
|
||||
if len(data['ids']) < 2:
|
||||
raise wizard.except_wizard("Warning",
|
||||
"Please select at least two inventories.")
|
||||
|
||||
|
||||
|
||||
for inventory in invent_obj.browse(cr, uid, data['ids'], context=context):
|
||||
if inventory.state == "done":
|
||||
raise wizard.except_wizard("Warning",
|
||||
"Merging is only allowed on draft inventories.")
|
||||
|
||||
for line in inventory.inventory_line_id:
|
||||
key = (line.location_id.id, line.product_id.id, line.product_uom.id)
|
||||
if key in invent_lines:
|
||||
invent_lines[key] += line.product_qty
|
||||
else:
|
||||
invent_lines[key] = line.product_qty
|
||||
|
||||
|
||||
new_invent = invent_obj.create(cr, uid, {
|
||||
'name': 'Merged inventory'
|
||||
}, context=context)
|
||||
|
||||
for key, quantity in invent_lines.items():
|
||||
invent_line_obj.create(cr, uid, {
|
||||
'inventory_id': new_invent,
|
||||
'location_id': key[0],
|
||||
'product_id': key[1],
|
||||
'product_uom': key[2],
|
||||
'product_qty': quantity,
|
||||
})
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
class merge_inventory(wizard.interface):
|
||||
states = {
|
||||
'init' : {
|
||||
'actions' : [],
|
||||
'result' : {'type' : 'form',
|
||||
'arch' : _form,
|
||||
'fields' : {},
|
||||
'state' : [('end', 'Cancel'),
|
||||
('merge', 'Yes') ]}
|
||||
},
|
||||
'merge' : {
|
||||
'actions' : [],
|
||||
'result' : {'type' : 'action',
|
||||
'action': do_merge,
|
||||
'state' : 'end'}
|
||||
},
|
||||
}
|
||||
merge_inventory("inventory.merge")
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
#
|
||||
# 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 wizard
|
||||
import pooler
|
||||
|
||||
|
||||
_form = """<?xml version="1.0"?>
|
||||
<form string="Set Stock to Zero">
|
||||
<separator colspan="4" string="Set Stocks to Zero" />
|
||||
<label string="Do you want to set stocks to zero ?"/>
|
||||
</form>
|
||||
"""
|
||||
|
||||
|
||||
def do_merge(self, cr, uid, data, context):
|
||||
invent_obj = pooler.get_pool(cr.dbname).get('stock.inventory')
|
||||
invent_line_obj = pooler.get_pool(cr.dbname).get('stock.inventory.line')
|
||||
prod_obj = pooler.get_pool(cr.dbname).get('product.product')
|
||||
|
||||
if len(data['ids']) <> 1:
|
||||
raise wizard.except_wizard("Warning",
|
||||
"Please select one and only one inventory!")
|
||||
|
||||
cr.execute('select distinct location_id from stock_inventory_line where inventory_id=%d', (data['ids'][0],))
|
||||
loc_ids = map(lambda x: x[0], cr.fetchall())
|
||||
locs = ','.join(map(lambda x: str(x), loc_ids))
|
||||
|
||||
cr.execute('select distinct location_id,product_id from stock_inventory_line where inventory_id=%d', (data['ids'][0],))
|
||||
inv = cr.fetchall()
|
||||
|
||||
cr.execute('select distinct product_id from stock_move where (location_dest_id in ('+locs+')) or (location_id in ('+locs+'))')
|
||||
stock = cr.fetchall()
|
||||
for s in stock:
|
||||
for loc in loc_ids:
|
||||
if (loc,s[0]) not in inv:
|
||||
p = prod_obj.browse(cr, uid, s[0])
|
||||
invent_line_obj.create(cr, uid, {
|
||||
'inventory_id': data['ids'][0],
|
||||
'location_id': loc,
|
||||
'product_id': s[0],
|
||||
'product_uom': p.uom_id.id,
|
||||
'product_qty': 0.0,
|
||||
})
|
||||
return {}
|
||||
|
||||
|
||||
class merge_inventory(wizard.interface):
|
||||
states = {
|
||||
'init' : {
|
||||
'actions' : [],
|
||||
'result' : {'type' : 'form',
|
||||
'arch' : _form,
|
||||
'fields' : {},
|
||||
'state' : [('end', 'Cancel'),
|
||||
('merge', 'Set to Zero') ]}
|
||||
},
|
||||
'merge' : {
|
||||
'actions' : [],
|
||||
'result' : {'type' : 'action',
|
||||
'action': do_merge,
|
||||
'state' : 'end'}
|
||||
},
|
||||
}
|
||||
merge_inventory("inventory.merge.stock.zero")
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# -*- 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_no_autopicking
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
{
|
||||
"name":"Stock No Auto-Picking",
|
||||
"version":"1.0",
|
||||
"author":"Tiny",
|
||||
"category":"Generic Modules/Production",
|
||||
"description": """
|
||||
This module allows an intermediate picking process to provide raw materials
|
||||
to production orders.
|
||||
|
||||
One example of usage of this module is to manage production made by your
|
||||
suppliers (sub-contracting). To achieve this, set the assembled product
|
||||
which is sub-contracted to "No Auto-Picking" and put the location of the
|
||||
supplier in the routing of the assembly operation.
|
||||
""",
|
||||
"depends":["mrp"],
|
||||
"demo_xml":[],
|
||||
"update_xml":["stock_no_autopicking_view.xml"],
|
||||
"active":False,
|
||||
"installable":True,
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
#
|
||||
# $Id: stock.py 1005 2005-07-25 08:41:42Z nicoe $
|
||||
#
|
||||
# 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 netsvc
|
||||
from osv import fields,osv
|
||||
|
||||
class product(osv.osv):
|
||||
_inherit = "product.product"
|
||||
_columns = {
|
||||
'auto_pick': fields.boolean('Auto Picking', help="Auto picking for raw materials of production orders.")
|
||||
}
|
||||
_defaults = {
|
||||
'auto_pick': lambda *args: True
|
||||
}
|
||||
product()
|
||||
|
||||
class mrp_production(osv.osv):
|
||||
_inherit = "mrp.production"
|
||||
def _get_auto_picking(self, cr, uid, production):
|
||||
return production.product_id.auto_pick
|
||||
mrp_production()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view" id="view_product_form_auto_pick">
|
||||
<field name="name">product.normal.auto_pick.form</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="product.product_normal_form_view" />
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_manager" position="after">
|
||||
<field name="auto_pick" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
Loading…
Reference in New Issue