[IMP] pricelists improvements. Was PR #8228
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from openerp import api, fields, models, _
|
from openerp import api, fields, models, _
|
||||||
from openerp.exceptions import UserError
|
|
||||||
|
|
||||||
|
|
||||||
class AccountAnalyticLine(models.Model):
|
class AccountAnalyticLine(models.Model):
|
||||||
@@ -21,17 +20,17 @@ class AccountAnalyticLine(models.Model):
|
|||||||
partner_id = fields.Many2one('res.partner', related='account_id.partner_id', string='Partner', store=True)
|
partner_id = fields.Many2one('res.partner', related='account_id.partner_id', string='Partner', store=True)
|
||||||
|
|
||||||
@api.v8
|
@api.v8
|
||||||
@api.onchange('product_id', 'product_uom_id')
|
@api.onchange('product_id', 'product_uom_id', 'unit_amount', 'currency_id')
|
||||||
def on_change_unit_amount(self):
|
def on_change_unit_amount(self):
|
||||||
product_price_type_obj = self.env['product.price.type']
|
if not self.product_id:
|
||||||
|
return {}
|
||||||
|
|
||||||
result = 0.0
|
result = 0.0
|
||||||
unit = False
|
prod_accounts = self.product_id.product_tmpl_id._get_product_accounts()
|
||||||
if self.product_id:
|
unit = self.product_uom_id.id
|
||||||
unit = self.product_uom_id.id
|
account = prod_accounts['expense']
|
||||||
if not self.product_uom_id or self.product_id.uom_id.category_id.id != self.product_uom_id.category_id.id:
|
if not unit or self.product_id.uom_po_id.category_id.id != unit.category_id.id:
|
||||||
unit = self.product_id.uom_id.id
|
unit = self.product_id.uom_po_id.id
|
||||||
account = self.product_id.property_account_income_id.id or self.product_id.categ_id.property_account_income_categ_id.id
|
|
||||||
if not account: account = False
|
|
||||||
|
|
||||||
ctx = dict(self._context or {})
|
ctx = dict(self._context or {})
|
||||||
if unit:
|
if unit:
|
||||||
@@ -39,16 +38,10 @@ class AccountAnalyticLine(models.Model):
|
|||||||
# to return a default price for those units
|
# to return a default price for those units
|
||||||
ctx['uom'] = unit
|
ctx['uom'] = unit
|
||||||
|
|
||||||
pricetype = False
|
# Compute based on pricetype
|
||||||
amount_unit = 0.0
|
amount_unit = self.product_id.with_context(ctx).price_get('standard_price')[self.product_id.id]
|
||||||
if self.product_id:
|
|
||||||
# Compute based on pricetype
|
|
||||||
pricetype = product_price_type_obj.search([('field', '=', 'list_price')], limit=1)
|
|
||||||
amount_unit = self.product_id.with_context(ctx).price_get(pricetype.field)[self.product_id.id]
|
|
||||||
amount = amount_unit * self.unit_amount or 0.0
|
amount = amount_unit * self.unit_amount or 0.0
|
||||||
result = round(amount, self.currency_id.decimal_places)
|
result = round(amount, self.currency_id.decimal_places) * -1
|
||||||
if pricetype and pricetype.field != 'list_price':
|
|
||||||
result *= -1
|
|
||||||
self.amount = result
|
self.amount = result
|
||||||
self.general_account_id = account
|
self.general_account_id = account
|
||||||
self.product_uom_id = unit
|
self.product_uom_id = unit
|
||||||
|
|||||||
@@ -703,7 +703,7 @@ class WizardMultiChartsAccounts(models.TransientModel):
|
|||||||
|
|
||||||
# When we install the CoA of first company, set the currency to price types and pricelists
|
# When we install the CoA of first company, set the currency to price types and pricelists
|
||||||
if company.id == 1:
|
if company.id == 1:
|
||||||
for reference in ['product.list_price', 'product.standard_price', 'product.list0', 'purchase.list0']:
|
for reference in ['product.list_price', 'product.standard_price', 'product.list0']:
|
||||||
try:
|
try:
|
||||||
tmp2 = self.env.ref(reference).write({'currency_id': self.currency_id.id})
|
tmp2 = self.env.ref(reference).write({'currency_id': self.currency_id.id})
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ access_hr_expense_report_manager,hr.expense.report.manager,model_hr_expense_repo
|
|||||||
access_product_product_hr_expense_user,product.product.hr.expense.user,product.model_product_product,base.group_hr_user,1,1,1,1
|
access_product_product_hr_expense_user,product.product.hr.expense.user,product.model_product_product,base.group_hr_user,1,1,1,1
|
||||||
access_product_template_hr_expense_user,product.template.hr.expense.user,product.model_product_template,base.group_hr_user,1,1,1,1
|
access_product_template_hr_expense_user,product.template.hr.expense.user,product.model_product_template,base.group_hr_user,1,1,1,1
|
||||||
access_product_uom_hr_expense_user,product.uom.hr.expense.user,product.model_product_uom,base.group_hr_user,1,1,1,1
|
access_product_uom_hr_expense_user,product.uom.hr.expense.user,product.model_product_uom,base.group_hr_user,1,1,1,1
|
||||||
access_product_price_type_user,product.price.type.user,product.model_product_price_type,base.group_hr_user,1,1,1,1
|
|
||||||
access_account_journal_user,account.journal.user,account.model_account_journal,base.group_hr_user,1,1,1,1
|
access_account_journal_user,account.journal.user,account.model_account_journal,base.group_hr_user,1,1,1,1
|
||||||
access_account_journal_employee,account.journal.employee,account.model_account_journal,base.group_user,1,0,0,0
|
access_account_journal_employee,account.journal.employee,account.model_account_journal,base.group_user,1,0,0,0
|
||||||
access_account_invoice_user,account.invoice.user,account.model_account_invoice,base.group_hr_user,1,1,1,1
|
access_account_invoice_user,account.invoice.user,account.model_account_invoice,base.group_hr_user,1,1,1,1
|
||||||
|
|||||||
|
@@ -62,13 +62,9 @@ access_product_category_mrp_manager,product.category mrp_manager,product.model_p
|
|||||||
access_product_template_mrp_manager,product.template mrp_manager,product.model_product_template,mrp.group_mrp_manager,1,1,1,1
|
access_product_template_mrp_manager,product.template mrp_manager,product.model_product_template,mrp.group_mrp_manager,1,1,1,1
|
||||||
access_product_product_mrp_manager,product.product mrp_manager,product.model_product_product,mrp.group_mrp_manager,1,1,1,1
|
access_product_product_mrp_manager,product.product mrp_manager,product.model_product_product,mrp.group_mrp_manager,1,1,1,1
|
||||||
access_product_packaging_mrp_manager,product.packaging mrp_manager,product.model_product_packaging,mrp.group_mrp_manager,1,1,1,1
|
access_product_packaging_mrp_manager,product.packaging mrp_manager,product.model_product_packaging,mrp.group_mrp_manager,1,1,1,1
|
||||||
access_pricelist_partnerinfo_mrp_manager,pricelist.partnerinfo mrp_manager,product.model_pricelist_partnerinfo,mrp.group_mrp_manager,1,1,1,1
|
|
||||||
access_product_price_type_mrp_manager,product.price.type mrp_manager,product.model_product_price_type,mrp.group_mrp_manager,1,1,1,1
|
|
||||||
access_product_pricelist_type_mrp_manager,product.pricelist.type mrp_manager,product.model_product_pricelist_type,mrp.group_mrp_manager,1,1,1,1
|
|
||||||
access_product_pricelist_mrp_manager,product.pricelist mrp_manager,product.model_product_pricelist,mrp.group_mrp_manager,1,1,1,1
|
access_product_pricelist_mrp_manager,product.pricelist mrp_manager,product.model_product_pricelist,mrp.group_mrp_manager,1,1,1,1
|
||||||
access_ir_property_group_product_mrp_manager,ir_property group_product_mrp_manager,base.model_ir_property,mrp.group_mrp_manager,1,1,1,1
|
access_ir_property_group_product_mrp_manager,ir_property group_product_mrp_manager,base.model_ir_property,mrp.group_mrp_manager,1,1,1,1
|
||||||
access_product_group_res_partner_mrp_manager,res_partner group_mrp_manager,base.model_res_partner,mrp.group_mrp_manager,1,1,1,0
|
access_product_group_res_partner_mrp_manager,res_partner group_mrp_manager,base.model_res_partner,mrp.group_mrp_manager,1,1,1,0
|
||||||
access_product_pricelist_version_mrp_manager,product.pricelist.version mrp_manager,product.model_product_pricelist_version,mrp.group_mrp_manager,1,1,1,1
|
|
||||||
access_product_pricelist_item_mrp_manager,product.pricelist.item mrp_manager,product.model_product_pricelist_item,mrp.group_mrp_manager,1,1,1,1
|
access_product_pricelist_item_mrp_manager,product.pricelist.item mrp_manager,product.model_product_pricelist_item,mrp.group_mrp_manager,1,1,1,1
|
||||||
access_resource_calendar_manufacturinguser,resource.calendar manufacturing.user,resource.model_resource_calendar,mrp.group_mrp_user,1,0,0,0
|
access_resource_calendar_manufacturinguser,resource.calendar manufacturing.user,resource.model_resource_calendar,mrp.group_mrp_user,1,0,0,0
|
||||||
access_account_journal_mrp_manager,account.journal mrp manager,account.model_account_journal,mrp.group_mrp_manager,1,0,0,0
|
access_account_journal_mrp_manager,account.journal mrp manager,account.model_account_journal,mrp.group_mrp_manager,1,0,0,0
|
||||||
|
|||||||
|
@@ -173,7 +173,7 @@ class mrp_repair(osv.osv):
|
|||||||
'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').next_by_code(cr, uid, 'mrp.repair'),
|
'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').next_by_code(cr, uid, 'mrp.repair'),
|
||||||
'invoice_method': lambda *a: 'none',
|
'invoice_method': lambda *a: 'none',
|
||||||
'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.repair', context=context),
|
'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.repair', context=context),
|
||||||
'pricelist_id': lambda self, cr, uid, context: self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'sale')])[0],
|
'pricelist_id': lambda self, cr, uid, context: self.pool['product.pricelist'].search(cr, uid, [], limit=1)[0],
|
||||||
'product_qty': 1.0,
|
'product_qty': 1.0,
|
||||||
'location_id': _default_stock_location,
|
'location_id': _default_stock_location,
|
||||||
}
|
}
|
||||||
@@ -229,7 +229,7 @@ class mrp_repair(osv.osv):
|
|||||||
return {'value': {
|
return {'value': {
|
||||||
'address_id': False,
|
'address_id': False,
|
||||||
'partner_invoice_id': False,
|
'partner_invoice_id': False,
|
||||||
'pricelist_id': pricelist_obj.search(cr, uid, [('type', '=', 'sale')])[0]
|
'pricelist_id': pricelist_obj.search(cr, uid, [], limit=1)[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addr = part_obj.address_get(cr, uid, [part], ['delivery', 'invoice', 'contact'])
|
addr = part_obj.address_get(cr, uid, [part], ['delivery', 'invoice', 'contact'])
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ access_stock_production_lot_user,stock.production.lot user,stock.model_stock_pro
|
|||||||
access_stock_production_lot_manager,stock.production.lot manager,stock.model_stock_production_lot,stock.group_stock_manager,1,0,0,0
|
access_stock_production_lot_manager,stock.production.lot manager,stock.model_stock_production_lot,stock.group_stock_manager,1,0,0,0
|
||||||
access_mrp_repair_line_user,mrp.repair.line user,model_mrp_repair_line,stock.group_stock_user,1,1,1,1
|
access_mrp_repair_line_user,mrp.repair.line user,model_mrp_repair_line,stock.group_stock_user,1,1,1,1
|
||||||
access_mrp_repair_line_manager,mrp.repair.line manager,model_mrp_repair_line,stock.group_stock_manager,1,0,0,0
|
access_mrp_repair_line_manager,mrp.repair.line manager,model_mrp_repair_line,stock.group_stock_manager,1,0,0,0
|
||||||
access_product_price_type_manager,product.price.type manager,product.model_product_price_type,stock.group_stock_manager,1,0,0,0
|
|
||||||
access_product_price_type_user,product.price.type,product.model_product_price_type,stock.group_stock_user,1,1,1,1
|
|
||||||
access_account_tax_user,account.tax,account.model_account_tax,stock.group_stock_user,1,1,1,1
|
access_account_tax_user,account.tax,account.model_account_tax,stock.group_stock_user,1,1,1,1
|
||||||
access_account_tax_manager,account.tax manager,account.model_account_tax,stock.group_stock_manager,1,0,0,0
|
access_account_tax_manager,account.tax manager,account.model_account_tax,stock.group_stock_manager,1,0,0,0
|
||||||
access_mrp_repair_fee_user_mrp,MRP Repair Fee user mrp,model_mrp_repair_fee,stock.group_stock_user,1,1,1,1
|
access_mrp_repair_fee_user_mrp,MRP Repair Fee user mrp,model_mrp_repair_fee,stock.group_stock_user,1,1,1,1
|
||||||
|
|||||||
|
@@ -179,7 +179,7 @@ class pos_config(osv.osv):
|
|||||||
return res and res[0] or False
|
return res and res[0] or False
|
||||||
|
|
||||||
def _default_pricelist(self, cr, uid, context=None):
|
def _default_pricelist(self, cr, uid, context=None):
|
||||||
res = self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'sale')], limit=1, context=context)
|
res = self.pool.get('product.pricelist').search(cr, uid, [], limit=1, context=context)
|
||||||
return res and res[0] or False
|
return res and res[0] or False
|
||||||
|
|
||||||
def _get_default_location(self, cr, uid, context=None):
|
def _get_default_location(self, cr, uid, context=None):
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ class res_partner(osv.osv):
|
|||||||
'property_product_pricelist': fields.property(
|
'property_product_pricelist': fields.property(
|
||||||
type='many2one',
|
type='many2one',
|
||||||
relation='product.pricelist',
|
relation='product.pricelist',
|
||||||
domain=[('type','=','sale')],
|
|
||||||
string="Sale Pricelist",
|
string="Sale Pricelist",
|
||||||
help="This pricelist will be used, instead of the default one, for sales to the current partner"),
|
help="This pricelist will be used, instead of the default one, for sales to the current partner"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<field name="name">res.partner.product.property.form.inherit</field>
|
<field name="name">res.partner.product.property.form.inherit</field>
|
||||||
<field name="model">res.partner</field>
|
<field name="model">res.partner</field>
|
||||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||||
<field name="groups_id" eval="[(4, ref('product.group_sale_pricelist')), (4, ref('product.group_purchase_pricelist'))]"/>
|
<field name="groups_id" eval="[(4, ref('product.group_sale_pricelist'))]"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<group name="sale">
|
<group name="sale">
|
||||||
<field name="property_product_pricelist" groups="product.group_sale_pricelist" attrs="{'invisible': [('is_company','=',False),('parent_id','!=',False)]}"/>
|
<field name="property_product_pricelist" groups="product.group_sale_pricelist" attrs="{'invisible': [('is_company','=',False),('parent_id','!=',False)]}"/>
|
||||||
|
|||||||
+103
-258
@@ -5,79 +5,18 @@ from itertools import chain
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from openerp import tools
|
from openerp import tools
|
||||||
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
import openerp.addons.decimal_precision as dp
|
import openerp.addons.decimal_precision as dp
|
||||||
from openerp.exceptions import UserError
|
from openerp.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class price_type(osv.osv):
|
|
||||||
"""
|
|
||||||
The price type is used to points which field in the product form
|
|
||||||
is a price and in which currency is this price expressed.
|
|
||||||
When a field is a price, you can use it in pricelists to base
|
|
||||||
sale and purchase prices based on some fields of the product.
|
|
||||||
"""
|
|
||||||
def _price_field_get(self, cr, uid, context=None):
|
|
||||||
mf = self.pool.get('ir.model.fields')
|
|
||||||
ids = mf.search(cr, uid, [('model','in', (('product.product'),('product.template'))), ('ttype','=','float')], context=context)
|
|
||||||
res = []
|
|
||||||
for field in mf.browse(cr, uid, ids, context=context):
|
|
||||||
if not (field.name, field.field_description) in res:
|
|
||||||
res.append((field.name, field.field_description))
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _get_field_currency(self, cr, uid, fname, ctx):
|
|
||||||
ids = self.search(cr, uid, [('field','=',fname)], context=ctx)
|
|
||||||
return self.browse(cr, uid, ids, context=ctx)[0].currency_id
|
|
||||||
|
|
||||||
def _get_currency(self, cr, uid, ctx):
|
|
||||||
comp = self.pool.get('res.users').browse(cr,uid,uid).company_id
|
|
||||||
if not comp:
|
|
||||||
comp_id = self.pool.get('res.company').search(cr, uid, [])[0]
|
|
||||||
comp = self.pool.get('res.company').browse(cr, uid, comp_id)
|
|
||||||
return comp.currency_id.id
|
|
||||||
|
|
||||||
_name = "product.price.type"
|
|
||||||
_description = "Price Type"
|
|
||||||
_columns = {
|
|
||||||
"name" : fields.char("Price Name", required=True, translate=True, help="Name of this kind of price."),
|
|
||||||
"active" : fields.boolean("Active"),
|
|
||||||
"field" : fields.selection(_price_field_get, "Product Field", size=32, required=True, help="Associated field in the product form."),
|
|
||||||
"currency_id" : fields.many2one('res.currency', "Currency", required=True, help="The currency the field is expressed in."),
|
|
||||||
}
|
|
||||||
_defaults = {
|
|
||||||
"active": lambda *args: True,
|
|
||||||
"currency_id": _get_currency
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
# Price lists
|
# Price lists
|
||||||
#----------------------------------------------------------
|
#----------------------------------------------------------
|
||||||
|
|
||||||
class product_pricelist_type(osv.osv):
|
|
||||||
_name = "product.pricelist.type"
|
|
||||||
_description = "Pricelist Type"
|
|
||||||
_columns = {
|
|
||||||
'name': fields.char('Name', required=True, translate=True),
|
|
||||||
'key': fields.char('Key', required=True, help="Used in the code to select specific prices based on the context. Keep unchanged."),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class product_pricelist(osv.osv):
|
class product_pricelist(osv.osv):
|
||||||
def _pricelist_type_get(self, cr, uid, context=None):
|
|
||||||
pricelist_type_obj = self.pool.get('product.pricelist.type')
|
|
||||||
pricelist_type_ids = pricelist_type_obj.search(cr, uid, [], order='name')
|
|
||||||
pricelist_types = pricelist_type_obj.read(cr, uid, pricelist_type_ids, ['key','name'], context=context)
|
|
||||||
|
|
||||||
res = []
|
|
||||||
|
|
||||||
for type in pricelist_types:
|
|
||||||
res.append((type['key'],type['name']))
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
_name = "product.pricelist"
|
_name = "product.pricelist"
|
||||||
_description = "Pricelist"
|
_description = "Pricelist"
|
||||||
@@ -85,8 +24,7 @@ class product_pricelist(osv.osv):
|
|||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Pricelist Name', required=True, translate=True),
|
'name': fields.char('Pricelist Name', required=True, translate=True),
|
||||||
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the pricelist without removing it."),
|
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the pricelist without removing it."),
|
||||||
'type': fields.selection(_pricelist_type_get, 'Pricelist Type', required=True),
|
'item_ids': fields.one2many('product.pricelist.item', 'pricelist_id', 'Pricelist Items', copy=True),
|
||||||
'version_id': fields.one2many('product.pricelist.version', 'pricelist_id', 'Pricelist Versions', copy=True),
|
|
||||||
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
|
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
|
||||||
'company_id': fields.many2one('res.company', 'Company'),
|
'company_id': fields.many2one('res.company', 'Company'),
|
||||||
}
|
}
|
||||||
@@ -139,7 +77,6 @@ class product_pricelist(osv.osv):
|
|||||||
return super(product_pricelist, self).name_search(
|
return super(product_pricelist, self).name_search(
|
||||||
cr, uid, name, args, operator=operator, context=context, limit=limit)
|
cr, uid, name, args, operator=operator, context=context, limit=limit)
|
||||||
|
|
||||||
|
|
||||||
def _get_currency(self, cr, uid, ctx):
|
def _get_currency(self, cr, uid, ctx):
|
||||||
comp = self.pool.get('res.users').browse(cr, uid, uid).company_id
|
comp = self.pool.get('res.users').browse(cr, uid, uid).company_id
|
||||||
if not comp:
|
if not comp:
|
||||||
@@ -152,9 +89,6 @@ class product_pricelist(osv.osv):
|
|||||||
"currency_id": _get_currency
|
"currency_id": _get_currency
|
||||||
}
|
}
|
||||||
|
|
||||||
def price_get_multi(self, cr, uid, ids, products_by_qty_by_partner, context=None):
|
|
||||||
return dict((key, dict((key, price[0]) for key, price in value.items())) for key, value in self.price_rule_get_multi(cr, uid, ids, products_by_qty_by_partner, context=context).items())
|
|
||||||
|
|
||||||
def price_rule_get_multi(self, cr, uid, ids, products_by_qty_by_partner, context=None):
|
def price_rule_get_multi(self, cr, uid, ids, products_by_qty_by_partner, context=None):
|
||||||
"""multi products 'price_get'.
|
"""multi products 'price_get'.
|
||||||
@param ids:
|
@param ids:
|
||||||
@@ -169,7 +103,7 @@ class product_pricelist(osv.osv):
|
|||||||
results = {}
|
results = {}
|
||||||
for pricelist in self.browse(cr, uid, ids, context=context):
|
for pricelist in self.browse(cr, uid, ids, context=context):
|
||||||
subres = self._price_rule_get_multi(cr, uid, pricelist, products_by_qty_by_partner, context=context)
|
subres = self._price_rule_get_multi(cr, uid, pricelist, products_by_qty_by_partner, context=context)
|
||||||
for product_id,price in subres.items():
|
for product_id, price in subres.items():
|
||||||
results.setdefault(product_id, {})
|
results.setdefault(product_id, {})
|
||||||
results[product_id][pricelist.id] = price
|
results[product_id][pricelist.id] = price
|
||||||
return results
|
return results
|
||||||
@@ -179,25 +113,13 @@ class product_pricelist(osv.osv):
|
|||||||
|
|
||||||
def _price_rule_get_multi(self, cr, uid, pricelist, products_by_qty_by_partner, context=None):
|
def _price_rule_get_multi(self, cr, uid, pricelist, products_by_qty_by_partner, context=None):
|
||||||
context = context or {}
|
context = context or {}
|
||||||
date = context.get('date') or time.strftime('%Y-%m-%d')
|
date = context.get('date') and context['date'][0:10] or time.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
date = date[0:10]
|
|
||||||
|
|
||||||
products = map(lambda x: x[0], products_by_qty_by_partner)
|
products = map(lambda x: x[0], products_by_qty_by_partner)
|
||||||
currency_obj = self.pool.get('res.currency')
|
|
||||||
product_obj = self.pool.get('product.template')
|
|
||||||
product_uom_obj = self.pool.get('product.uom')
|
product_uom_obj = self.pool.get('product.uom')
|
||||||
price_type_obj = self.pool.get('product.price.type')
|
|
||||||
|
|
||||||
if not products:
|
if not products:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
version = False
|
|
||||||
for v in pricelist.version_id:
|
|
||||||
if ((v.date_start is False) or (v.date_start <= date)) and ((v.date_end is False) or (v.date_end >= date)):
|
|
||||||
version = v
|
|
||||||
break
|
|
||||||
if not version:
|
|
||||||
raise UserError(_("At least one pricelist has no active version !\nPlease create or activate one."))
|
|
||||||
categ_ids = {}
|
categ_ids = {}
|
||||||
for p in products:
|
for p in products:
|
||||||
categ = p.categ_id
|
categ = p.categ_id
|
||||||
@@ -220,22 +142,20 @@ class product_pricelist(osv.osv):
|
|||||||
cr.execute(
|
cr.execute(
|
||||||
'SELECT i.id '
|
'SELECT i.id '
|
||||||
'FROM product_pricelist_item AS i '
|
'FROM product_pricelist_item AS i '
|
||||||
'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = any(%s)) '
|
'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = any(%s))'
|
||||||
'AND (product_id IS NULL OR (product_id = any(%s))) '
|
'AND (product_id IS NULL OR product_id = any(%s))'
|
||||||
'AND ((categ_id IS NULL) OR (categ_id = any(%s))) '
|
'AND (categ_id IS NULL OR categ_id = any(%s)) '
|
||||||
'AND (price_version_id = %s) '
|
'AND (pricelist_id = %s) '
|
||||||
'ORDER BY sequence, min_quantity desc',
|
'AND ((i.date_start IS NULL OR i.date_start<=%s) AND (i.date_end IS NULL OR i.date_end>=%s))'
|
||||||
(prod_tmpl_ids, prod_ids, categ_ids, version.id))
|
'ORDER BY applied_on, min_quantity desc',
|
||||||
|
(prod_tmpl_ids, prod_ids, categ_ids, pricelist.id, date, date))
|
||||||
|
|
||||||
item_ids = [x[0] for x in cr.fetchall()]
|
item_ids = [x[0] for x in cr.fetchall()]
|
||||||
items = self.pool.get('product.pricelist.item').browse(cr, uid, item_ids, context=context)
|
items = self.pool.get('product.pricelist.item').browse(cr, uid, item_ids, context=context)
|
||||||
|
|
||||||
price_types = {}
|
|
||||||
|
|
||||||
results = {}
|
results = {}
|
||||||
for product, qty, partner in products_by_qty_by_partner:
|
for product, qty, partner in products_by_qty_by_partner:
|
||||||
results[product.id] = 0.0
|
results[product.id] = 0.0
|
||||||
rule_id = False
|
suitable_rule = False
|
||||||
|
|
||||||
# Final unit price is computed according to `qty` in the `qty_uom_id` UoM.
|
# Final unit price is computed according to `qty` in the `qty_uom_id` UoM.
|
||||||
# An intermediary unit price may be computed according to a different UoM, in
|
# An intermediary unit price may be computed according to a different UoM, in
|
||||||
@@ -252,9 +172,10 @@ class product_pricelist(osv.osv):
|
|||||||
# Ignored - incompatible UoM in context, use default product UoM
|
# Ignored - incompatible UoM in context, use default product UoM
|
||||||
pass
|
pass
|
||||||
|
|
||||||
price_type = 'standard_price' if pricelist.type == 'purchase' else 'list_price'
|
|
||||||
# if Public user try to access standard price from website sale, need to call _price_get.
|
# if Public user try to access standard price from website sale, need to call _price_get.
|
||||||
price = product_obj._price_get(cr, uid, [product], price_type, context=context)[product.id] or False
|
price = self.pool['product.template']._price_get(cr, uid, [product], 'list_price', context=context)[product.id]
|
||||||
|
|
||||||
|
price_uom_id = qty_uom_id
|
||||||
for rule in items:
|
for rule in items:
|
||||||
if rule.min_quantity and qty_in_product_uom < rule.min_quantity:
|
if rule.min_quantity and qty_in_product_uom < rule.min_quantity:
|
||||||
continue
|
continue
|
||||||
@@ -271,68 +192,50 @@ class product_pricelist(osv.osv):
|
|||||||
if rule.product_id and product.id != rule.product_id.id:
|
if rule.product_id and product.id != rule.product_id.id:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if rule.base == -1:
|
if rule.base == 'pricelist' and rule.base_pricelist_id:
|
||||||
if rule.base_pricelist_id:
|
price_tmp = self._price_get_multi(cr, uid, rule.base_pricelist_id, [(product, qty, partner)], context=context)[product.id]
|
||||||
price_tmp = self._price_get_multi(cr, uid,
|
ptype_src = rule.base_pricelist_id.currency_id.id
|
||||||
rule.base_pricelist_id, [(product,
|
price = self.pool['res.currency'].compute(cr, uid, ptype_src, pricelist.currency_id.id, price_tmp, round=False, context=context)
|
||||||
qty, partner)], context=context)[product.id]
|
|
||||||
ptype_src = rule.base_pricelist_id.currency_id.id
|
|
||||||
price_uom_id = qty_uom_id
|
|
||||||
price = currency_obj.compute(cr, uid,
|
|
||||||
ptype_src, pricelist.currency_id.id,
|
|
||||||
price_tmp, round=False,
|
|
||||||
context=context)
|
|
||||||
else:
|
else:
|
||||||
if rule.base not in price_types:
|
# if base option is public price take sale price else cost price of product
|
||||||
price_types[rule.base] = price_type_obj.browse(cr, uid, int(rule.base))
|
|
||||||
price_type = price_types[rule.base]
|
|
||||||
|
|
||||||
# price_get returns the price in the context UoM, i.e. qty_uom_id
|
# price_get returns the price in the context UoM, i.e. qty_uom_id
|
||||||
price_uom_id = qty_uom_id
|
price = self.pool['product.template']._price_get(cr, uid, [product], rule.base, context=context)[product.id]
|
||||||
price = currency_obj.compute(
|
|
||||||
cr, uid,
|
convert_to_price_uom = (lambda price: product_uom_obj._compute_price(
|
||||||
price_type.currency_id.id, pricelist.currency_id.id,
|
cr, uid, product.uom_id.id,
|
||||||
product_obj._price_get(cr, uid, [product], price_type.field, context=context)[product.id],
|
price, price_uom_id))
|
||||||
round=False, context=context)
|
|
||||||
for seller in product.seller_ids:
|
|
||||||
partner = partner.id if partner and not isinstance(partner, int) else partner
|
|
||||||
if seller.name.id == partner:
|
|
||||||
qty_in_seller = qty
|
|
||||||
seller_uom = seller.product_uom and seller.product_uom.id or False
|
|
||||||
if qty_uom_id != seller_uom:
|
|
||||||
qty_in_seller = product_uom_obj._compute_qty(cr, uid, qty_uom_id, qty, to_uom_id=seller_uom)
|
|
||||||
for line in seller.pricelist_ids:
|
|
||||||
if line.min_quantity <= qty_in_seller:
|
|
||||||
price = line.price
|
|
||||||
|
|
||||||
if price is not False:
|
if price is not False:
|
||||||
price_limit = price
|
if rule.compute_price == 'fixed':
|
||||||
price = price * (1.0+(rule.price_discount or 0.0))
|
price = convert_to_price_uom(rule.fixed_price)
|
||||||
if rule.price_round:
|
elif rule.compute_price == 'percentage':
|
||||||
price = tools.float_round(price, precision_rounding=rule.price_round)
|
price = (price - (price * (rule.percent_price / 100))) or 0.0
|
||||||
|
else:
|
||||||
|
#complete formula
|
||||||
|
price_limit = price
|
||||||
|
price = (price - (price * (rule.price_discount / 100))) or 0.0
|
||||||
|
if rule.price_round:
|
||||||
|
price = tools.float_round(price, precision_rounding=rule.price_round)
|
||||||
|
|
||||||
convert_to_price_uom = (lambda price: product_uom_obj._compute_price(
|
if rule.price_surcharge:
|
||||||
cr, uid, product.uom_id.id,
|
price_surcharge = convert_to_price_uom(rule.price_surcharge)
|
||||||
price, price_uom_id))
|
price += price_surcharge
|
||||||
if rule.price_surcharge:
|
|
||||||
price_surcharge = convert_to_price_uom(rule.price_surcharge)
|
|
||||||
price += price_surcharge
|
|
||||||
|
|
||||||
if rule.price_min_margin:
|
if rule.price_min_margin:
|
||||||
price_min_margin = convert_to_price_uom(rule.price_min_margin)
|
price_min_margin = convert_to_price_uom(rule.price_min_margin)
|
||||||
price = max(price, price_limit + price_min_margin)
|
price = max(price, price_limit + price_min_margin)
|
||||||
|
|
||||||
if rule.price_max_margin:
|
if rule.price_max_margin:
|
||||||
price_max_margin = convert_to_price_uom(rule.price_max_margin)
|
price_max_margin = convert_to_price_uom(rule.price_max_margin)
|
||||||
price = min(price, price_limit + price_max_margin)
|
price = min(price, price_limit + price_max_margin)
|
||||||
|
suitable_rule = rule
|
||||||
rule_id = rule.id
|
|
||||||
break
|
break
|
||||||
|
# Final price conversion into pricelist currency
|
||||||
|
if suitable_rule and suitable_rule.compute_price != 'fixed' and suitable_rule.base != 'pricelist':
|
||||||
|
user_company = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id
|
||||||
|
price = self.pool['res.currency'].compute(cr, uid, user_company.currency_id.id, pricelist.currency_id.id, price, context=context)
|
||||||
|
|
||||||
# Final price conversion to target UoM
|
results[product.id] = (price, suitable_rule and suitable_rule.id or False)
|
||||||
price = product_uom_obj._compute_price(cr, uid, price_uom_id, price, qty_uom_id)
|
|
||||||
|
|
||||||
results[product.id] = (price, rule_id)
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def price_get(self, cr, uid, ids, prod_id, qty, partner=None, context=None):
|
def price_get(self, cr, uid, ids, prod_id, qty, partner=None, context=None):
|
||||||
@@ -344,104 +247,15 @@ class product_pricelist(osv.osv):
|
|||||||
res = res_multi[prod_id]
|
res = res_multi[prod_id]
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
class product_pricelist_version(osv.osv):
|
|
||||||
_name = "product.pricelist.version"
|
|
||||||
_description = "Pricelist Version"
|
|
||||||
_columns = {
|
|
||||||
'pricelist_id': fields.many2one('product.pricelist', 'Price List',
|
|
||||||
required=True, select=True, ondelete='cascade'),
|
|
||||||
'name': fields.char('Name', required=True, translate=True),
|
|
||||||
'active': fields.boolean('Active',
|
|
||||||
help="When a version is duplicated it is set to non active, so that the " \
|
|
||||||
"dates do not overlaps with original version. You should change the dates " \
|
|
||||||
"and reactivate the pricelist"),
|
|
||||||
'items_id': fields.one2many('product.pricelist.item',
|
|
||||||
'price_version_id', 'Price List Items', required=True, copy=True),
|
|
||||||
'date_start': fields.date('Start Date', help="First valid date for the version."),
|
|
||||||
'date_end': fields.date('End Date', help="Last valid date for the version."),
|
|
||||||
'company_id': fields.related('pricelist_id','company_id',type='many2one',
|
|
||||||
readonly=True, relation='res.company', string='Company', store=True)
|
|
||||||
}
|
|
||||||
_defaults = {
|
|
||||||
'active': lambda *a: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _check_date(self, cursor, user, ids, context=None):
|
|
||||||
for pricelist_version in self.browse(cursor, user, ids, context=context):
|
|
||||||
if not pricelist_version.active:
|
|
||||||
continue
|
|
||||||
where = []
|
|
||||||
if pricelist_version.date_start:
|
|
||||||
where.append("((date_end>='%s') or (date_end is null))" % (pricelist_version.date_start,))
|
|
||||||
if pricelist_version.date_end:
|
|
||||||
where.append("((date_start<='%s') or (date_start is null))" % (pricelist_version.date_end,))
|
|
||||||
|
|
||||||
cursor.execute('SELECT id ' \
|
|
||||||
'FROM product_pricelist_version ' \
|
|
||||||
'WHERE '+' and '.join(where) + (where and ' and ' or '')+
|
|
||||||
'pricelist_id = %s ' \
|
|
||||||
'AND active ' \
|
|
||||||
'AND id <> %s', (
|
|
||||||
pricelist_version.pricelist_id.id,
|
|
||||||
pricelist_version.id))
|
|
||||||
if cursor.fetchall():
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
_constraints = [
|
|
||||||
(_check_date, 'You cannot have 2 pricelist versions that overlap!',
|
|
||||||
['date_start', 'date_end'])
|
|
||||||
]
|
|
||||||
|
|
||||||
def copy(self, cr, uid, id, default=None, context=None):
|
|
||||||
# set active False to prevent overlapping active pricelist
|
|
||||||
# versions
|
|
||||||
if not default:
|
|
||||||
default = {}
|
|
||||||
default['active'] = False
|
|
||||||
return super(product_pricelist_version, self).copy(cr, uid, id, default, context=context)
|
|
||||||
|
|
||||||
class product_pricelist_item(osv.osv):
|
class product_pricelist_item(osv.osv):
|
||||||
def _price_field_get(self, cr, uid, context=None):
|
|
||||||
pt = self.pool.get('product.price.type')
|
|
||||||
ids = pt.search(cr, uid, [], context=context)
|
|
||||||
result = []
|
|
||||||
for line in pt.browse(cr, uid, ids, context=context):
|
|
||||||
result.append((line.id, line.name))
|
|
||||||
|
|
||||||
result.append((-1, _('Other Pricelist')))
|
|
||||||
return result
|
|
||||||
|
|
||||||
# Added default function to fetch the Price type Based on Pricelist type.
|
|
||||||
def _get_default_base(self, cr, uid, fields, context=None):
|
|
||||||
product_price_type_obj = self.pool.get('product.price.type')
|
|
||||||
if fields.get('type') == 'purchase':
|
|
||||||
product_price_type_ids = product_price_type_obj.search(cr, uid, [('field', '=', 'standard_price')], context=context)
|
|
||||||
elif fields.get('type') == 'sale':
|
|
||||||
product_price_type_ids = product_price_type_obj.search(cr, uid, [('field','=','list_price')], context=context)
|
|
||||||
else:
|
|
||||||
return -1
|
|
||||||
if not product_price_type_ids:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
pricetype = product_price_type_obj.browse(cr, uid, product_price_type_ids, context=context)[0]
|
|
||||||
return pricetype.id
|
|
||||||
|
|
||||||
_name = "product.pricelist.item"
|
_name = "product.pricelist.item"
|
||||||
_description = "Pricelist item"
|
_description = "Pricelist item"
|
||||||
_order = "sequence, min_quantity desc"
|
_order = "applied_on, min_quantity desc"
|
||||||
_defaults = {
|
|
||||||
'base': _get_default_base,
|
|
||||||
'min_quantity': lambda *a: 0,
|
|
||||||
'sequence': lambda *a: 5,
|
|
||||||
'price_discount': lambda *a: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _check_recursion(self, cr, uid, ids, context=None):
|
def _check_recursion(self, cr, uid, ids, context=None):
|
||||||
for obj_list in self.browse(cr, uid, ids, context=context):
|
for obj_list in self.browse(cr, uid, ids, context=context):
|
||||||
if obj_list.base == -1:
|
if obj_list.base == 'pricelist':
|
||||||
main_pricelist = obj_list.price_version_id.pricelist_id.id
|
main_pricelist = obj_list.pricelist_id.id
|
||||||
other_pricelist = obj_list.base_pricelist_id.id
|
other_pricelist = obj_list.base_pricelist_id.id
|
||||||
if main_pricelist == other_pricelist:
|
if main_pricelist == other_pricelist:
|
||||||
return False
|
return False
|
||||||
@@ -453,26 +267,48 @@ class product_pricelist_item(osv.osv):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _get_pricelist_item_name_price(self, cr, uid, ids, fields, args, context=None):
|
||||||
|
"""This function is used to set some fields used for usability purposes only (state explicitly what a rule does)
|
||||||
|
"""
|
||||||
|
res = {}
|
||||||
|
for item in self.browse(cr, uid, ids, context=context):
|
||||||
|
res[item.id] = {'name': '', 'price': ''}
|
||||||
|
if item.categ_id:
|
||||||
|
res[item.id]['name'] = _("Category: %s") % (item.categ_id.name)
|
||||||
|
elif item.product_tmpl_id:
|
||||||
|
res[item.id]['name'] = item.product_tmpl_id.name
|
||||||
|
elif item.product_id:
|
||||||
|
res[item.id]['name'] = item.product_id.display_name.replace('[%s]' % item.product_id.code, '')
|
||||||
|
else:
|
||||||
|
res[item.id]['name'] = _("All Products")
|
||||||
|
|
||||||
|
if item.compute_price == 'fixed':
|
||||||
|
res[item.id]['price'] = ("%s %s") % (item.fixed_price, item.pricelist_id.currency_id.name)
|
||||||
|
elif item.compute_price == 'percentage':
|
||||||
|
res[item.id]['price'] = _("%s %% discount") % (item.percent_price)
|
||||||
|
else:
|
||||||
|
res[item.id]['price'] = _("%s %% discount and %s surcharge") % (abs(item.price_discount), item.price_surcharge)
|
||||||
|
return res
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Rule Name', help="Explicit rule name for this pricelist line."),
|
|
||||||
'price_version_id': fields.many2one('product.pricelist.version', 'Price List Version', required=True, select=True, ondelete='cascade'),
|
|
||||||
'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade', help="Specify a template if this rule only applies to one product template. Keep empty otherwise."),
|
'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade', help="Specify a template if this rule only applies to one product template. Keep empty otherwise."),
|
||||||
'product_id': fields.many2one('product.product', 'Product', ondelete='cascade', help="Specify a product if this rule only applies to one product. Keep empty otherwise."),
|
'product_id': fields.many2one('product.product', 'Product', ondelete='cascade', help="Specify a product if this rule only applies to one product. Keep empty otherwise."),
|
||||||
'categ_id': fields.many2one('product.category', 'Product Category', ondelete='cascade', help="Specify a product category if this rule only applies to products belonging to this category or its children categories. Keep empty otherwise."),
|
'categ_id': fields.many2one('product.category', 'Product Category', ondelete='cascade', help="Specify a product category if this rule only applies to products belonging to this category or its children categories. Keep empty otherwise."),
|
||||||
'min_quantity': fields.integer('Min. Quantity', required=True,
|
'min_quantity': fields.integer('Min. Quantity',
|
||||||
help="For the rule to apply, bought/sold quantity must be greater "
|
help="For the rule to apply, bought/sold quantity must be greater "
|
||||||
"than or equal to the minimum quantity specified in this field.\n"
|
"than or equal to the minimum quantity specified in this field.\n"
|
||||||
"Expressed in the default unit of measure of the product."
|
"Expressed in the default unit of measure of the product."
|
||||||
),
|
),
|
||||||
|
'applied_on': fields.selection([('3_global', 'Global'),('2_product_category', ' Product Category'), ('1_product', 'Product'), ('0_product_variant', 'Product Variant')], string="Apply On", required=True,
|
||||||
|
help='Pricelist Item applicable on selected option'),
|
||||||
'sequence': fields.integer('Sequence', required=True, help="Gives the order in which the pricelist items will be checked. The evaluation gives highest priority to lowest sequence and stops as soon as a matching item is found."),
|
'sequence': fields.integer('Sequence', required=True, help="Gives the order in which the pricelist items will be checked. The evaluation gives highest priority to lowest sequence and stops as soon as a matching item is found."),
|
||||||
'base': fields.selection(_price_field_get, 'Based on', required=True,
|
'base': fields.selection([('list_price', 'Public Price'), ('standard_price', 'Cost'), ('pricelist', 'Other Pricelist')], string="Based on", required=True,
|
||||||
size=-1, # here use size=-1 to store the values as integers
|
help='Base price for computation. \n Public Price: The base price will be the Sale/public Price. \n Cost Price : The base price will be the cost price. \n Other Pricelist : Computation of the base price based on another Pricelist.'),
|
||||||
help='Base price for computation. \n Public Price: The base price will be the Sale/public Price. \n Vendor Section on Product or Cost Price : The base price will be the vendor price if it is set, otherwise it will be the cost price. \n Other Pricelist : Computation of the base price based on another Pricelist.'),
|
|
||||||
'base_pricelist_id': fields.many2one('product.pricelist', 'Other Pricelist'),
|
'base_pricelist_id': fields.many2one('product.pricelist', 'Other Pricelist'),
|
||||||
|
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist'),
|
||||||
'price_surcharge': fields.float('Price Surcharge',
|
'price_surcharge': fields.float('Price Surcharge',
|
||||||
digits_compute= dp.get_precision('Product Price'), help='Specify the fixed amount to add or substract(if negative) to the amount calculated with the discount.'),
|
digits_compute= dp.get_precision('Product Price'), help='Specify the fixed amount to add or substract(if negative) to the amount calculated with the discount.'),
|
||||||
'price_discount': fields.float('Price Discount', digits=(16,4)),
|
'price_discount': fields.float('Price Discount', digits=(16,2)),
|
||||||
'price_round': fields.float('Price Rounding',
|
'price_round': fields.float('Price Rounding',
|
||||||
digits_compute= dp.get_precision('Product Price'),
|
digits_compute= dp.get_precision('Product Price'),
|
||||||
help="Sets the price so that it is a multiple of this value.\n" \
|
help="Sets the price so that it is a multiple of this value.\n" \
|
||||||
@@ -483,19 +319,28 @@ class product_pricelist_item(osv.osv):
|
|||||||
digits_compute= dp.get_precision('Product Price'), help='Specify the minimum amount of margin over the base price.'),
|
digits_compute= dp.get_precision('Product Price'), help='Specify the minimum amount of margin over the base price.'),
|
||||||
'price_max_margin': fields.float('Max. Price Margin',
|
'price_max_margin': fields.float('Max. Price Margin',
|
||||||
digits_compute= dp.get_precision('Product Price'), help='Specify the maximum amount of margin over the base price.'),
|
digits_compute= dp.get_precision('Product Price'), help='Specify the maximum amount of margin over the base price.'),
|
||||||
'company_id': fields.related('price_version_id','company_id',type='many2one',
|
'company_id': fields.related('pricelist_id','company_id',type='many2one',
|
||||||
readonly=True, relation='res.company', string='Company', store=True)
|
readonly=True, relation='res.company', string='Company', store=True),
|
||||||
|
'currency_id': fields.related('pricelist_id', 'currency_id', type='many2one',
|
||||||
|
readonly=True, relation='res.currency', string='Currency', store=True),
|
||||||
|
'date_start': fields.date('Start Date', help="Starting date for the pricelist item validation"),
|
||||||
|
'date_end': fields.date('End Date', help="Ending valid for the pricelist item validation"),
|
||||||
|
'compute_price': fields.selection([('fixed', 'Fix Price'), ('percentage', 'Percentage (discount)'), ('formula', 'Formula')], select=True, default='fixed'),
|
||||||
|
'fixed_price': fields.float('Fixed Price'),
|
||||||
|
'percent_price': fields.float('Percentage Price'),
|
||||||
|
#functional fields used for usability purposes
|
||||||
|
'name': fields.function(_get_pricelist_item_name_price, type="char", string='Name', multi='item_name_price', help="Explicit rule name for this pricelist line."),
|
||||||
|
'price': fields.function(_get_pricelist_item_name_price, type="char", string='Price', multi='item_name_price', help="Explicit rule name for this pricelist line."),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_defaults = {
|
||||||
|
'base': 'list_price',
|
||||||
|
'min_quantity': 1,
|
||||||
|
'sequence': 5,
|
||||||
|
'price_discount': 0,
|
||||||
|
'applied_on': '3_global',
|
||||||
|
}
|
||||||
_constraints = [
|
_constraints = [
|
||||||
(_check_recursion, 'Error! You cannot assign the Main Pricelist as Other Pricelist in PriceList Item!', ['base_pricelist_id']),
|
(_check_recursion, 'Error! You cannot assign the Main Pricelist as Other Pricelist in PriceList Item!', ['base_pricelist_id']),
|
||||||
(_check_margin, 'Error! The minimum margin should be lower than the maximum margin.', ['price_min_margin', 'price_max_margin'])
|
(_check_margin, 'Error! The minimum margin should be lower than the maximum margin.', ['price_min_margin', 'price_max_margin'])
|
||||||
]
|
]
|
||||||
|
|
||||||
def product_id_change(self, cr, uid, ids, product_id, context=None):
|
|
||||||
if not product_id:
|
|
||||||
return {}
|
|
||||||
prod = self.pool.get('product.product').read(cr, uid, [product_id], ['code','name'])
|
|
||||||
if prod[0]['code']:
|
|
||||||
return {'value': {'name': prod[0]['code']}}
|
|
||||||
return {}
|
|
||||||
|
|||||||
@@ -7,77 +7,19 @@
|
|||||||
<menuitem id="menu_product_pricelist_main" name="Pricelists"
|
<menuitem id="menu_product_pricelist_main" name="Pricelists"
|
||||||
parent="base.menu_sale_config" groups="product.group_sale_pricelist" sequence="3"/>
|
parent="base.menu_sale_config" groups="product.group_sale_pricelist" sequence="3"/>
|
||||||
|
|
||||||
<record id="product_pricelist_version_form_view" model="ir.ui.view">
|
|
||||||
<field name="name">product.pricelist.version.form</field>
|
|
||||||
<field name="model">product.pricelist.version</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Pricelist Version">
|
|
||||||
<group>
|
|
||||||
<group>
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="pricelist_id"/>
|
|
||||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
|
||||||
</group>
|
|
||||||
<group>
|
|
||||||
<field name="date_start"/>
|
|
||||||
<field name="date_end"/>
|
|
||||||
<field name="active"/>
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
<notebook>
|
|
||||||
<page string="Item List">
|
|
||||||
<field name="items_id"/>
|
|
||||||
</page>
|
|
||||||
</notebook>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record id="product_pricelist_version_tree_view" model="ir.ui.view">
|
|
||||||
<field name="name">product.pricelist.version.tree</field>
|
|
||||||
<field name="model">product.pricelist.version</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree string="Pricelist Version">
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="pricelist_id"/>
|
|
||||||
<field name="date_start"/>
|
|
||||||
<field name="date_end"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_pricelist_action" model="ir.actions.act_window">
|
|
||||||
<field name="name">Pricelist Versions</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">product.pricelist.version</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_id" ref="product_pricelist_version_tree_view"/>
|
|
||||||
<field name="help" type="html">
|
|
||||||
<p class="oe_view_nocontent_create">
|
|
||||||
Click to add a pricelist version.
|
|
||||||
</p><p>
|
|
||||||
There can be more than one version of a pricelist, each of
|
|
||||||
these must be valid during a certain period of time. Some
|
|
||||||
examples of versions: Main Prices, 2010, 2011, Summer Sales,
|
|
||||||
etc.
|
|
||||||
</p>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<menuitem
|
|
||||||
action="product_pricelist_action" id="menu_product_pricelist_action"
|
|
||||||
parent="product.menu_product_pricelist_main" sequence="2"/>
|
|
||||||
|
|
||||||
<record id="product_pricelist_item_tree_view" model="ir.ui.view">
|
<record id="product_pricelist_item_tree_view" model="ir.ui.view">
|
||||||
<field name="name">product.pricelist.item.tree</field>
|
<field name="name">product.pricelist.item.tree</field>
|
||||||
<field name="model">product.pricelist.item</field>
|
<field name="model">product.pricelist.item</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="Products Listprices Items">
|
<tree string="Pricelist Items">
|
||||||
<field name="sequence"/>
|
<field name="sequence" widget="handle"/>
|
||||||
<field colspan="4" name="name"/>
|
<field colspan="4" name="name"/>
|
||||||
<field name="product_id" groups="product.group_product_variant"/>
|
<field name="product_id" groups="product.group_product_variant"/>
|
||||||
<field name="product_tmpl_id"/>
|
<field name="product_tmpl_id"/>
|
||||||
<field name="categ_id"/>
|
<field name="categ_id"/>
|
||||||
<field name="min_quantity"/>
|
<field name="min_quantity"/>
|
||||||
<field name="base"/>
|
<field name="date_start"/>
|
||||||
|
<field name="date_end"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -86,39 +28,55 @@
|
|||||||
<field name="name">product.pricelist.item.form</field>
|
<field name="name">product.pricelist.item.form</field>
|
||||||
<field name="model">product.pricelist.item</field>
|
<field name="model">product.pricelist.item</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Products Listprices Items">
|
<form string="Pricelist Items">
|
||||||
<label for="name" class="oe_edit_only"/>
|
|
||||||
<h1><field name="name"/></h1>
|
<h1><field name="name"/></h1>
|
||||||
|
<group>
|
||||||
<group col="4">
|
<group>
|
||||||
<field name="product_id" on_change="product_id_change(product_id)" groups="product.group_product_variant"/>
|
<field name="applied_on" widget="radio"/>
|
||||||
<field name="product_tmpl_id"/>
|
<field name="categ_id" attrs="{'invisible':[('applied_on', '!=', '2_product_category')], 'required':[('applied_on', '=', '2_product_category')]}"/>
|
||||||
<field name="categ_id"/>
|
<field name="product_tmpl_id" attrs="{'invisible':[('applied_on', '!=', '1_product')],'required':[('applied_on', '=', '1_product')]}" string="Product"/>
|
||||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
<field name="product_id" attrs="{'invisible':[('applied_on', '!=', '0_product_variant')],'required':[('applied_on', '=', '0_product_variant')]}" string="Product Variant"/>
|
||||||
<field name="min_quantity"/>
|
</group>
|
||||||
<field name="sequence"/>
|
<group>
|
||||||
|
<field name="min_quantity"/>
|
||||||
|
<field name="date_start"/>
|
||||||
|
<field name="date_end"/>
|
||||||
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<separator string="Price Computation"/>
|
<separator string="Price Computation"/>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<label for="compute_price" string="Compute Price"/>
|
||||||
|
<div>
|
||||||
|
<field name="compute_price" widget="radio"/>
|
||||||
|
<field name="currency_id" invisible="1"/>
|
||||||
|
<div attrs="{'invisible':[('compute_price', '!=', 'fixed')]}">
|
||||||
|
<field name="fixed_price" nolabel= "1" widget='monetary' options="{'currency_field': 'currency_id'}"/></div>
|
||||||
|
<div attrs="{'invisible':[('compute_price', '!=', 'percentage')]}">
|
||||||
|
<field name="percent_price" nolabel="1" class="oe_inline"/>%%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
<div class="oe_grey" groups="product.group_uom">
|
<div class="oe_grey" groups="product.group_uom">
|
||||||
<p>The computed price is expressed in the default Unit of Measure of the product.</p>
|
<p>The computed price is expressed in the default Unit of Measure of the product.</p>
|
||||||
</div>
|
</div>
|
||||||
<group col="4">
|
<group attrs="{'invisible':[('compute_price', '!=', 'formula')]}">
|
||||||
<field name="base"/>
|
<group col="6" colspan="6">
|
||||||
<field name="base_pricelist_id" attrs="{'invisible':[('base', '!=', -1)],'required': [('base','=', -1)], 'readonly': [('base','!=', -1)]}"/>
|
<field name="base" colspan="6"/>
|
||||||
|
<label string="New Price ="/>
|
||||||
|
<label string="Public Price - " attrs="{'invisible':[('base', 'not in', ('list_price','standard_price'))]}"/>
|
||||||
|
<label string="Other Pricelist - " attrs="{'invisible':[('base', '!=', 'pricelist')]}"/>
|
||||||
|
<div><field name="price_discount" nolabel="1" class="oe_inline"/>%%</div>
|
||||||
|
<label string=" + "/>
|
||||||
|
<field name="price_surcharge" nolabel="1"/>
|
||||||
|
<newline/>
|
||||||
|
<field name="price_round" string="Rounding Method"/>
|
||||||
|
<field name="price_min_margin" string="Min. Margin"/>
|
||||||
|
<field name="price_max_margin" string="Max. Margin"/>
|
||||||
|
<field name="base_pricelist_id" attrs="{'invisible':[('base', '!=', 'pricelist')],'required': [('base','=', 'pricelist')], 'readonly': [('base','!=', 'pricelist')]}"/>
|
||||||
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group col="6" colspan="5">
|
|
||||||
<label string="New Price ="/>
|
|
||||||
<label string="Base Price"/>
|
|
||||||
<label string="* ( 1 + "/>
|
|
||||||
<field name="price_discount" nolabel="1"/>
|
|
||||||
<label string=" ) + "/>
|
|
||||||
<field name="price_surcharge" nolabel="1"/>
|
|
||||||
<newline/>
|
|
||||||
<field name="price_round" string="Rounding Method"/>
|
|
||||||
<field name="price_min_margin" string="Min. Margin"/>
|
|
||||||
<field name="price_max_margin" string="Max. Margin"/>
|
|
||||||
</group>
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -129,8 +87,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<search string="Products Price Search">
|
<search string="Products Price Search">
|
||||||
<field name="name" string="Products Price"/>
|
<field name="name" string="Products Price"/>
|
||||||
<field name="type"/>
|
<field name="active"/>
|
||||||
<field name="active" />
|
|
||||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
<field name="currency_id" groups="base.group_multi_currency"/>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
@@ -143,9 +100,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="Products Price List">
|
<tree string="Products Price List">
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="type"/>
|
|
||||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
<field name="currency_id" groups="base.group_multi_currency"/>
|
||||||
<field name="active" />
|
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -154,33 +109,34 @@
|
|||||||
<field name="model">product.pricelist</field>
|
<field name="model">product.pricelist</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Products Price List">
|
<form string="Products Price List">
|
||||||
<label for="name" class="oe_edit_only"/>
|
<sheet>
|
||||||
<h1>
|
<div class="oe_title">
|
||||||
<field name="name"/>
|
<h1>
|
||||||
</h1>
|
|
||||||
<group col="4">
|
|
||||||
<field name="active"/>
|
|
||||||
<field name="type"/>
|
|
||||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
|
||||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
|
||||||
</group>
|
|
||||||
<field name="version_id" context="{'type':type}">
|
|
||||||
<form string="Pricelist Version">
|
|
||||||
<group col="4">
|
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<group col="4">
|
||||||
|
<group>
|
||||||
<field name="active"/>
|
<field name="active"/>
|
||||||
<field name="date_start"/>
|
|
||||||
<field name="date_end"/>
|
|
||||||
</group>
|
</group>
|
||||||
<field name="items_id" context="{'type':parent.type}"/>
|
<group>
|
||||||
</form>
|
<field name="currency_id" groups="base.group_multi_currency"/>
|
||||||
<tree string="Pricelist Version">
|
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||||
<field name="name"/>
|
</group>
|
||||||
<field name="active"/>
|
</group>
|
||||||
<field name="date_start"/>
|
<div groups="product.group_pricelist_item">
|
||||||
<field name="date_end"/>
|
<separator string="Pricelist Items"/>
|
||||||
</tree>
|
<field name="item_ids" nolabel="1" context="{'default_base':'list_price'}">
|
||||||
</field>
|
<tree string="Pricelist Items">
|
||||||
|
<field name="name" string="Applicable On"/>
|
||||||
|
<field name="min_quantity"/>
|
||||||
|
<field name="date_start"/>
|
||||||
|
<field name="date_end"/>
|
||||||
|
<field name="price" string="Price"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</div>
|
||||||
|
</sheet>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -191,7 +147,7 @@
|
|||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="search_view_id" ref="product_pricelist_view_search" />
|
<field name="search_view_id" ref="product_pricelist_view_search" />
|
||||||
<field name="context">{"default_type":"sale", "search_default_type":"sale"}</field>
|
<field name="context">{"default_base":'list_price'}</field>
|
||||||
<field name="help" type="html">
|
<field name="help" type="html">
|
||||||
<p class="oe_view_nocontent_create">
|
<p class="oe_view_nocontent_create">
|
||||||
Click to create a pricelist.
|
Click to create a pricelist.
|
||||||
@@ -199,66 +155,15 @@
|
|||||||
A price list contains rules to be evaluated in order to compute
|
A price list contains rules to be evaluated in order to compute
|
||||||
the sales price of the products.
|
the sales price of the products.
|
||||||
</p><p>
|
</p><p>
|
||||||
Price lists may have several versions (2010, 2011, Promotion of
|
Each rule include a set of applicability criteria (date range,
|
||||||
February 2010, etc.) and each version may have several rules.
|
product category...) and a computation that easily helps to achieve
|
||||||
(e.g. the customer price of a product category will be based on
|
any kind of pricing.
|
||||||
the supplier price multiplied by 1.80).
|
|
||||||
</p>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record id="product_pricelist_action_for_purchase" model="ir.actions.act_window">
|
|
||||||
<field name="name">Pricelists</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">product.pricelist</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
<field name="search_view_id" ref="product_pricelist_view_search" />
|
|
||||||
<field name="context">{"default_type":"purchase", "search_default_type":"purchase"}</field>
|
|
||||||
<field name="help" type="html">
|
|
||||||
<p class="oe_view_nocontent_create">
|
|
||||||
Click to create a pricelist.
|
|
||||||
</p><p>
|
|
||||||
A price list contains rules to be evaluated in order to compute
|
|
||||||
the purchase price. The default price list has only one rule; use
|
|
||||||
the cost price defined on the product form, so that you do not have to
|
|
||||||
worry about supplier pricelists if you have very simple needs.
|
|
||||||
</p><p>
|
|
||||||
But you can also import complex price lists form your supplier
|
|
||||||
that may depends on the quantities ordered or the current
|
|
||||||
promotions.
|
|
||||||
</p>
|
</p>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
action="product_pricelist_action2" id="menu_product_pricelist_action2"
|
action="product_pricelist_action2" id="menu_product_pricelist_action2"
|
||||||
parent="product.menu_product_pricelist_main" sequence="1" groups="product.group_sale_pricelist"/>
|
parent="product.menu_product_pricelist_main" sequence="1" groups="product.group_sale_pricelist"/>
|
||||||
|
|
||||||
<record id="product_price_type_view" model="ir.ui.view">
|
|
||||||
<field name="name">product.price.type.form</field>
|
|
||||||
<field name="model">product.price.type</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Products Price Type">
|
|
||||||
<group col="4">
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="active"/>
|
|
||||||
<field name="field"/>
|
|
||||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
|
||||||
</group>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_price_type_action" model="ir.actions.act_window">
|
|
||||||
<field name="name">Price Types</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">product.price.type</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<menuitem
|
|
||||||
action="product_price_type_action" id="menu_product_price_type"
|
|
||||||
parent="product.menu_product_pricelist_main" sequence="4" groups="base.group_no_one"/>
|
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|||||||
+52
-39
@@ -7,7 +7,7 @@ import time
|
|||||||
from openerp import api, tools, SUPERUSER_ID
|
from openerp import api, tools, SUPERUSER_ID
|
||||||
from openerp.osv import osv, fields, expression
|
from openerp.osv import osv, fields, expression
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
import openerp.addons.decimal_precision as dp
|
import openerp.addons.decimal_precision as dp
|
||||||
@@ -400,7 +400,7 @@ class product_template(osv.osv):
|
|||||||
products = self.browse(cr, uid, ids, context=context)
|
products = self.browse(cr, uid, ids, context=context)
|
||||||
qtys = map(lambda x: (x, quantity, partner), products)
|
qtys = map(lambda x: (x, quantity, partner), products)
|
||||||
pl = plobj.browse(cr, uid, pricelist, context=context)
|
pl = plobj.browse(cr, uid, pricelist, context=context)
|
||||||
price = plobj._price_get_multi(cr,uid, pl, qtys, context=context)
|
price = plobj._price_get_multi(cr, uid, pl, qtys, context=context)
|
||||||
for id in ids:
|
for id in ids:
|
||||||
res[id] = price.get(id, 0.0)
|
res[id] = price.get(id, 0.0)
|
||||||
for id in ids:
|
for id in ids:
|
||||||
@@ -466,6 +466,28 @@ class product_template(osv.osv):
|
|||||||
return variant.write({name: value})
|
return variant.write({name: value})
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def _select_seller(self, cr, uid, ids, name, arg, context=None):
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
|
res = {}
|
||||||
|
partner = context.get('partner')
|
||||||
|
minimal_quantity = context.get('quantity', 0.0)
|
||||||
|
date = context.get('date', time.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||||
|
for product in self.browse(cr, uid, ids, context=context):
|
||||||
|
res[product.id] = False
|
||||||
|
for seller in product.seller_ids:
|
||||||
|
if seller.date_start and seller.date_start > date:
|
||||||
|
continue
|
||||||
|
if seller.date_end and seller.date_end < date:
|
||||||
|
continue
|
||||||
|
if partner and seller.name.id != partner:
|
||||||
|
continue
|
||||||
|
if minimal_quantity and minimal_quantity < seller.qty:
|
||||||
|
continue
|
||||||
|
res[product.id] = seller
|
||||||
|
break
|
||||||
|
return res
|
||||||
|
|
||||||
def _get_product_template_type(self, cr, uid, context=None):
|
def _get_product_template_type(self, cr, uid, context=None):
|
||||||
return [('consu', 'Consumable'), ('service', 'Service')]
|
return [('consu', 'Consumable'), ('service', 'Service')]
|
||||||
_get_product_template_type_wrapper = lambda self, *args, **kwargs: self._get_product_template_type(*args, **kwargs)
|
_get_product_template_type_wrapper = lambda self, *args, **kwargs: self._get_product_template_type(*args, **kwargs)
|
||||||
@@ -531,38 +553,35 @@ class product_template(osv.osv):
|
|||||||
help="Gives the different ways to package the same product. This has no impact on "
|
help="Gives the different ways to package the same product. This has no impact on "
|
||||||
"the picking order and is mainly used if you use the EDI module."),
|
"the picking order and is mainly used if you use the EDI module."),
|
||||||
'seller_ids': fields.one2many('product.supplierinfo', 'product_tmpl_id', 'Vendor'),
|
'seller_ids': fields.one2many('product.supplierinfo', 'product_tmpl_id', 'Vendor'),
|
||||||
'seller_delay': fields.related('seller_ids','delay', type='integer', string='Vendor Lead Time',
|
'selected_seller_id': fields.function(_select_seller, type='many2one', relation='product.supplierinfo', string='Selected Seller', help='Technical field that selects a seller based on priority (sequence) and an optional partner and/or a minimal quantity in the context'),
|
||||||
|
'seller_delay': fields.related('selected_seller_id','delay', type='integer', string='Vendor Lead Time',
|
||||||
help="This is the average delay in days between the purchase order confirmation and the receipts for this product and for the default vendor. It is used by the scheduler to order requests based on reordering delays."),
|
help="This is the average delay in days between the purchase order confirmation and the receipts for this product and for the default vendor. It is used by the scheduler to order requests based on reordering delays."),
|
||||||
'seller_qty': fields.related('seller_ids','qty', type='float', string='Vendor Quantity',
|
'seller_qty': fields.related('selected_seller_id','qty', type='float', string='Vendor Quantity',
|
||||||
help="This is minimum quantity to purchase from Main Vendor."),
|
help="This is minimum quantity to purchase from Main Vendor."),
|
||||||
'seller_id': fields.related('seller_ids','name', type='many2one', relation='res.partner', string='Main Vendor',
|
'seller_id': fields.related('selected_seller_id','name', type='many2one', relation='res.partner', string='Main Vendor',
|
||||||
help="Main vendor who has highest priority in vendor list."),
|
help="Main vendor who has highest priority in vendor list."),
|
||||||
|
'seller_price': fields.related('selected_seller_id','price', type='float', string='Vendor Price', help="Purchase price from from Main Vendor."),
|
||||||
|
|
||||||
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the product without removing it."),
|
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the product without removing it."),
|
||||||
'color': fields.integer('Color Index'),
|
'color': fields.integer('Color Index'),
|
||||||
'is_product_variant': fields.function( _is_product_variant, type='boolean', string='Is a product variant'),
|
'is_product_variant': fields.function(_is_product_variant, type='boolean', string='Is a product variant'),
|
||||||
|
|
||||||
'attribute_line_ids': fields.one2many('product.attribute.line', 'product_tmpl_id', 'Product Attributes'),
|
'attribute_line_ids': fields.one2many('product.attribute.line', 'product_tmpl_id', 'Product Attributes'),
|
||||||
'product_variant_ids': fields.one2many('product.product', 'product_tmpl_id', 'Products', required=True),
|
'product_variant_ids': fields.one2many('product.product', 'product_tmpl_id', 'Products', required=True),
|
||||||
'product_variant_count': fields.function( _get_product_variant_count, type='integer', string='# of Product Variants'),
|
'product_variant_count': fields.function(_get_product_variant_count, type='integer', string='# of Product Variants'),
|
||||||
|
|
||||||
# related to display product product information if is_product_variant
|
# related to display product product information if is_product_variant
|
||||||
'barcode': fields.related('product_variant_ids', 'barcode', type='char', string='Barcode', oldname='ean13'),
|
'barcode': fields.related('product_variant_ids', 'barcode', type='char', string='Barcode', oldname='ean13'),
|
||||||
'default_code': fields.related('product_variant_ids', 'default_code', type='char', string='Internal Reference'),
|
'default_code': fields.related('product_variant_ids', 'default_code', type='char', string='Internal Reference'),
|
||||||
|
'item_ids': fields.one2many('product.pricelist.item', 'product_tmpl_id', 'Pricelist Items'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _price_get_list_price(self, product):
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
def _price_get(self, cr, uid, products, ptype='list_price', context=None):
|
def _price_get(self, cr, uid, products, ptype='list_price', context=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
if 'currency_id' in context:
|
if 'currency_id' in context:
|
||||||
pricetype_obj = self.pool.get('product.price.type')
|
currency_id = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id.id
|
||||||
price_type_id = pricetype_obj.search(cr, uid, [('field','=',ptype)])[0]
|
|
||||||
price_type_currency_id = pricetype_obj.browse(cr,uid,price_type_id).currency_id.id
|
|
||||||
|
|
||||||
res = {}
|
res = {}
|
||||||
product_uom_obj = self.pool.get('product.uom')
|
product_uom_obj = self.pool.get('product.uom')
|
||||||
for product in products:
|
for product in products:
|
||||||
@@ -581,13 +600,12 @@ class product_template(osv.osv):
|
|||||||
uom = product.uom_id
|
uom = product.uom_id
|
||||||
res[product.id] = product_uom_obj._compute_price(cr, uid,
|
res[product.id] = product_uom_obj._compute_price(cr, uid,
|
||||||
uom.id, res[product.id], context['uom'])
|
uom.id, res[product.id], context['uom'])
|
||||||
# Convert from price_type currency to asked one
|
# Convert from current user company currency to asked one
|
||||||
if 'currency_id' in context:
|
if 'currency_id' in context:
|
||||||
# Take the price_type currency from the product field
|
# Take current user company currency.
|
||||||
# This is right cause a field cannot be in more than one currency
|
# This is right cause a field cannot be in more than one currency
|
||||||
res[product.id] = self.pool.get('res.currency').compute(cr, uid, price_type_currency_id,
|
res[product.id] = self.pool.get('res.currency').compute(cr, uid, currency_id,
|
||||||
context['currency_id'], res[product.id],context=context)
|
context['currency_id'], res[product.id], context=context)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _get_uom_id(self, cr, uid, *args):
|
def _get_uom_id(self, cr, uid, *args):
|
||||||
@@ -1173,6 +1191,8 @@ class product_packaging(osv.osv):
|
|||||||
class product_supplierinfo(osv.osv):
|
class product_supplierinfo(osv.osv):
|
||||||
_name = "product.supplierinfo"
|
_name = "product.supplierinfo"
|
||||||
_description = "Information about a product vendor"
|
_description = "Information about a product vendor"
|
||||||
|
_order = 'sequence, min_qty desc, price'
|
||||||
|
|
||||||
def _calc_qty(self, cr, uid, ids, fields, arg, context=None):
|
def _calc_qty(self, cr, uid, ids, fields, arg, context=None):
|
||||||
result = {}
|
result = {}
|
||||||
for supplier_info in self.browse(cr, uid, ids, context=context):
|
for supplier_info in self.browse(cr, uid, ids, context=context):
|
||||||
@@ -1183,37 +1203,30 @@ class product_supplierinfo(osv.osv):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name' : fields.many2one('res.partner', 'Vendor', required=True,domain = [('supplier','=',True)], ondelete='cascade', help="Vendor of this product"),
|
'name': fields.many2one('res.partner', 'Vendor', required=True, domain=[('supplier', '=', True)], ondelete='cascade', help="Vendor of this product"),
|
||||||
'product_name': fields.char('Vendor Product Name', help="This vendor's product name will be used when printing a request for quotation. Keep empty to use the internal one."),
|
'product_name': fields.char('Vendor Product Name', help="This vendor's product name will be used when printing a request for quotation. Keep empty to use the internal one."),
|
||||||
'product_code': fields.char('Vendor Product Code', help="This vendor's product code will be used when printing a request for quotation. Keep empty to use the internal one."),
|
'product_code': fields.char('Vendor Product Code', help="This vendor's product code will be used when printing a request for quotation. Keep empty to use the internal one."),
|
||||||
'sequence' : fields.integer('Sequence', help="Assigns the priority to the list of product vendor."),
|
'sequence': fields.integer('Sequence', help="Assigns the priority to the list of product vendor."),
|
||||||
'product_uom': fields.related('product_tmpl_id', 'uom_po_id', type='many2one', relation='product.uom', string="Vendor Unit of Measure", readonly="1", help="This comes from the product form."),
|
'product_uom': fields.related('product_tmpl_id', 'uom_po_id', type='many2one', relation='product.uom', string="Vendor Unit of Measure", readonly="1", help="This comes from the product form."),
|
||||||
'min_qty': fields.float('Minimal Quantity', required=True, help="The minimal quantity to purchase to this vendor, expressed in the vendor Product Unit of Measure if not empty, in the default unit of measure of the product otherwise."),
|
'min_qty': fields.float('Minimal Quantity', required=True, help="The minimal quantity to purchase from this vendor, expressed in the vendor Product Unit of Measure if not any, in the default unit of measure of the product otherwise."),
|
||||||
'qty': fields.function(_calc_qty, store=True, type='float', string='Quantity', multi="qty", help="This is a quantity which is converted into Default Unit of Measure."),
|
'qty': fields.function(_calc_qty, store=True, type='float', string='Quantity', multi="qty", help="This is a quantity which is converted into Default Unit of Measure."),
|
||||||
'product_tmpl_id' : fields.many2one('product.template', 'Product Template', required=True, ondelete='cascade', select=True, oldname='product_id'),
|
'price': fields.float('Price', required=True, digits_compute=dp.get_precision('Product Price'), help="The price to purchase a product"),
|
||||||
'delay' : fields.integer('Delivery Lead Time', required=True, help="Lead time in days between the confirmation of the purchase order and the receipt of the products in your warehouse. Used by the scheduler for automatic computation of the purchase order planning."),
|
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
|
||||||
'pricelist_ids': fields.one2many('pricelist.partnerinfo', 'suppinfo_id', 'Vendor Pricelist', copy=True),
|
'date_start': fields.date('Start Date', help="Start date for this vendor price"),
|
||||||
'company_id':fields.many2one('res.company', string='Company',select=1),
|
'date_end': fields.date('End Date', help="End date for this vendor price"),
|
||||||
|
'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade', select=True, oldname='product_id'),
|
||||||
|
'delay': fields.integer('Delivery Lead Time', required=True, help="Lead time in days between the confirmation of the purchase order and the receipt of the products in your warehouse. Used by the scheduler for automatic computation of the purchase order planning."),
|
||||||
|
'company_id': fields.many2one('res.company', string='Company', select=1),
|
||||||
}
|
}
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'min_qty': 0.0,
|
'min_qty': 0.0,
|
||||||
'sequence': 1,
|
'sequence': 1,
|
||||||
'delay': 1,
|
'delay': 1,
|
||||||
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'product.supplierinfo', context=c),
|
'price': 0.0,
|
||||||
|
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'product.supplierinfo', context=c),
|
||||||
|
'currency_id': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
_order = 'sequence'
|
|
||||||
|
|
||||||
|
|
||||||
class pricelist_partnerinfo(osv.osv):
|
|
||||||
_name = 'pricelist.partnerinfo'
|
|
||||||
_columns = {
|
|
||||||
'name': fields.char('Description'),
|
|
||||||
'suppinfo_id': fields.many2one('product.supplierinfo', 'Partner Information', required=True, ondelete='cascade'),
|
|
||||||
'min_quantity': fields.float('Quantity', required=True, help="The minimal quantity to trigger this rule, expressed in the vendor Unit of Measure if any or in the default Unit of Measure of the product otherrwise."),
|
|
||||||
'price': fields.float('Unit Price', required=True, digits_compute=dp.get_precision('Product Price'), help="This price will be considered as a price for the vendor Unit of Measure if any or the default Unit of Measure of the product otherwise"),
|
|
||||||
}
|
|
||||||
_order = 'min_quantity asc'
|
|
||||||
|
|
||||||
class res_currency(osv.osv):
|
class res_currency(osv.osv):
|
||||||
_inherit = 'res.currency'
|
_inherit = 'res.currency'
|
||||||
|
|||||||
@@ -182,48 +182,20 @@ parameter) will see those record just disappear.
|
|||||||
<field name="object">product.product</field>
|
<field name="object">product.product</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!--
|
<!-- Price list -->
|
||||||
Resource: product.price.type
|
|
||||||
-->
|
|
||||||
<record id="list_price" model="product.price.type">
|
|
||||||
<field name="name">Public Price</field>
|
|
||||||
<field name="field">list_price</field>
|
|
||||||
</record>
|
|
||||||
<record id="standard_price" model="product.price.type">
|
|
||||||
<field name="name">Vendor Section on Product or Cost Price</field>
|
|
||||||
<field name="field">standard_price</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Price list type
|
|
||||||
-->
|
|
||||||
<record id="pricelist_type_sale" model="product.pricelist.type">
|
|
||||||
<field name="name">Sale Pricelist</field>
|
|
||||||
<field name="key">sale</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Price list
|
|
||||||
-->
|
|
||||||
<record id="list0" model="product.pricelist">
|
<record id="list0" model="product.pricelist">
|
||||||
<field name="name">Public Pricelist</field>
|
<field name="name">Public Pricelist</field>
|
||||||
<field name="type">sale</field>
|
|
||||||
</record>
|
|
||||||
<record id="ver0" model="product.pricelist.version">
|
|
||||||
<field name="pricelist_id" ref="list0"/>
|
|
||||||
<field name="name">Default Public Pricelist Version</field>
|
|
||||||
</record>
|
|
||||||
<record id="item0" model="product.pricelist.item">
|
|
||||||
<field name="price_version_id" ref="ver0"/>
|
|
||||||
<field name="base" ref="list_price"/>
|
|
||||||
<field name="sequence">1000</field>
|
|
||||||
<field name="name">Default Public Pricelist Line</field>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- Price list item -->
|
||||||
|
|
||||||
|
<record id="item0" model="product.pricelist.item">
|
||||||
|
<field name="pricelist_id" ref="list0"/>
|
||||||
|
<field name="compute_price">formula</field>
|
||||||
|
<field name="base">list_price</field>
|
||||||
|
<field name="sequence">1000</field>
|
||||||
|
</record>
|
||||||
<!--
|
<!--
|
||||||
Property
|
Property
|
||||||
-->
|
-->
|
||||||
|
|||||||
@@ -891,6 +891,7 @@ QWERTY keyboard</field>
|
|||||||
<field name="name" ref="base.res_partner_1"/>
|
<field name="name" ref="base.res_partner_1"/>
|
||||||
<field name="delay">3</field>
|
<field name="delay">3</field>
|
||||||
<field name="min_qty">1</field>
|
<field name="min_qty">1</field>
|
||||||
|
<field name="price">750</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="product_supplierinfo_2" model="product.supplierinfo">
|
<record id="product_supplierinfo_2" model="product.supplierinfo">
|
||||||
@@ -898,6 +899,15 @@ QWERTY keyboard</field>
|
|||||||
<field name="name" ref="base.res_partner_4"/>
|
<field name="name" ref="base.res_partner_4"/>
|
||||||
<field name="delay">3</field>
|
<field name="delay">3</field>
|
||||||
<field name="min_qty">1</field>
|
<field name="min_qty">1</field>
|
||||||
|
<field name="price">790</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="product_supplierinfo_2bis" model="product.supplierinfo">
|
||||||
|
<field name="product_tmpl_id" ref="product_product_6_product_template"/>
|
||||||
|
<field name="name" ref="base.res_partner_4"/>
|
||||||
|
<field name="delay">3</field>
|
||||||
|
<field name="min_qty">3</field>
|
||||||
|
<field name="price">785</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="product_supplierinfo_3" model="product.supplierinfo">
|
<record id="product_supplierinfo_3" model="product.supplierinfo">
|
||||||
|
|||||||
@@ -5,58 +5,38 @@
|
|||||||
-
|
-
|
||||||
!record {model: product.pricelist, id: customer_pricelist}:
|
!record {model: product.pricelist, id: customer_pricelist}:
|
||||||
name: Customer Pricelist
|
name: Customer Pricelist
|
||||||
type: sale
|
item_ids:
|
||||||
version_id:
|
- name: Default pricelist
|
||||||
- name: v1.0
|
compute_price: 'formula'
|
||||||
date_start: 2012-01-01
|
base: 'pricelist'
|
||||||
items_id:
|
base_pricelist_id: list0
|
||||||
- name: Default pricelist
|
- name: 10% Discount on Assemble Computer
|
||||||
base: -1
|
applied_on : '1_product'
|
||||||
base_pricelist_id: list0
|
sequence: 1
|
||||||
- name: 10% Discount on Assemble Computer
|
product_id: product_product_4
|
||||||
sequence: 1
|
compute_price: 'formula'
|
||||||
product_id: product_product_4
|
base: 'list_price'
|
||||||
base: !eval (ref('product.list_price'))
|
price_discount: 10
|
||||||
price_discount: -0.10
|
- name: 1 surchange on Laptop
|
||||||
- name: 1 surchange on Laptop
|
applied_on : '1_product'
|
||||||
sequence: 1
|
sequence: 1
|
||||||
product_id: product_product_25
|
product_id: product_product_25
|
||||||
base: !eval (ref('product.list_price'))
|
compute_price: 'formula'
|
||||||
price_surcharge: 1
|
base: 'list_price'
|
||||||
- name: 5% Discount on all Computer related products
|
price_surcharge: 1
|
||||||
sequence: 1
|
- name: 5% Discount on all Computer related products
|
||||||
min_quantity: 2
|
applied_on : '2_product_category'
|
||||||
base: !eval (ref('product.list_price'))
|
sequence: 1
|
||||||
categ_id: product_category_5
|
min_quantity: 2
|
||||||
price_discount: -0.05
|
compute_price: 'formula'
|
||||||
- name: v2.0 (Special Discount on all products during last 5 days in current year)
|
base: 'list_price'
|
||||||
|
categ_id: product_category_5
|
||||||
|
price_discount: 5
|
||||||
|
- name: 30% Discount on all products
|
||||||
|
applied_on : '0_product_variant'
|
||||||
date_start: 2011-12-27
|
date_start: 2011-12-27
|
||||||
date_end: 2011-12-31
|
date_end: 2011-12-31
|
||||||
items_id:
|
compute_price: 'formula'
|
||||||
- name: 30% Discount on all products
|
price_discount: 30
|
||||||
price_discount: -0.30
|
sequence: 1
|
||||||
sequence: 1
|
base: 'list_price'
|
||||||
base: !eval (ref('product.list_price'))
|
|
||||||
-
|
|
||||||
!record {model: product.pricelist, id: supplier_pricelist}:
|
|
||||||
name: Vendor Pricelist
|
|
||||||
type: sale
|
|
||||||
version_id:
|
|
||||||
- name: v1.0
|
|
||||||
items_id:
|
|
||||||
- name: 20% Discount given by my supplier
|
|
||||||
sequence: 1
|
|
||||||
price_min_margin: 2
|
|
||||||
price_max_margin: 5
|
|
||||||
product_id: product_product_6
|
|
||||||
base: !eval (ref('product.standard_price'))
|
|
||||||
-
|
|
||||||
!record {model: pricelist.partnerinfo, id: supplier_pricelist0_product_pc2}:
|
|
||||||
suppinfo_id: product_supplierinfo_2
|
|
||||||
min_quantity: 3
|
|
||||||
price: 785
|
|
||||||
-
|
|
||||||
!record {model: pricelist.partnerinfo, id: supplier_pricelist1_product_pc2}:
|
|
||||||
suppinfo_id: product_supplierinfo_2
|
|
||||||
min_quantity: 1
|
|
||||||
price: 790
|
|
||||||
|
|||||||
@@ -133,6 +133,19 @@
|
|||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="Sales" attrs="{'invisible':[('sale_ok','=',False)]}" name="sales">
|
<page string="Sales" attrs="{'invisible':[('sale_ok','=',False)]}" name="sales">
|
||||||
|
<div name="pricelist_item" groups="product.group_product_pricelist">
|
||||||
|
<separator string="Pricing"/>
|
||||||
|
<field name="item_ids" nolabel="1" context="{'default_base':'list_price', 'default_applied_on' :'1'}">
|
||||||
|
<tree string="Pricelist Items" editable="bottom">
|
||||||
|
<field name="pricelist_id" string="Pricelist" required='1'/>
|
||||||
|
<field name="fixed_price" string="Price" required='1'/>
|
||||||
|
<field name="min_quantity"/>
|
||||||
|
<field name="date_start"/>
|
||||||
|
<field name="date_end"/>
|
||||||
|
<field name="applied_on" invisible="1"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</div>
|
||||||
<group name="sale">
|
<group name="sale">
|
||||||
<group name="sale_condition" string="Sale Conditions">
|
<group name="sale_condition" string="Sale Conditions">
|
||||||
<label for="warranty"/>
|
<label for="warranty"/>
|
||||||
@@ -760,30 +773,33 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Vendor Information">
|
<form string="Vendor Information">
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group string="Vendor">
|
||||||
<field name="name" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}"/>
|
<field name="name" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}"/>
|
||||||
<field name="min_qty"/>
|
|
||||||
<field name="product_uom" groups="product.group_uom"/>
|
|
||||||
<field name="delay"/>
|
|
||||||
</group><group>
|
|
||||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
|
||||||
<field name="product_name"/>
|
<field name="product_name"/>
|
||||||
<field name="product_code"/>
|
<field name="product_code"/>
|
||||||
|
<label for="delay"/>
|
||||||
|
<div>
|
||||||
|
<field name="delay" class="oe_inline"/> days
|
||||||
|
</div>
|
||||||
|
</group>
|
||||||
|
<group string="Price List">
|
||||||
|
<field name="product_tmpl_id" string="Product" invisible="context.get('visible_product_tmpl_id', True)"/>
|
||||||
|
<label for="min_qty"/>
|
||||||
|
<div>
|
||||||
|
<field name="min_qty" class="oe_inline"/>
|
||||||
|
<field name="product_uom" class="oe_inline" groups="product.group_uom"/>
|
||||||
|
</div>
|
||||||
|
<label for="price"/>
|
||||||
|
<div>
|
||||||
|
<field name="price" class="oe_inline"/><field name="currency_id" class="oe_inline" groups="base.group_multi_currency"/>
|
||||||
|
</div>
|
||||||
|
<label for="date_start" string="Validity"/>
|
||||||
|
<div><field name="date_start" class="oe_inline"/> to <field name="date_end" class="oe_inline"/></div>
|
||||||
|
</group>
|
||||||
|
<group string="Other Information" groups="base.group_multi_company">
|
||||||
|
<field name="company_id" options="{'no_create': True}"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<p groups="product.group_purchase_pricelist" class="oe_grey">The prices below will only be taken into account when your pricelist is set as based on vendor prices.</p>
|
|
||||||
<field groups="product.group_purchase_pricelist" name="pricelist_ids">
|
|
||||||
<tree editable="bottom" string="Pricelist">
|
|
||||||
<field name="min_quantity"/>
|
|
||||||
<field name="price"/>
|
|
||||||
</tree>
|
|
||||||
<form>
|
|
||||||
<group>
|
|
||||||
<field name="min_quantity"/>
|
|
||||||
<field name="price"/>
|
|
||||||
</group>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -794,12 +810,23 @@
|
|||||||
<tree string="Vendor Information">
|
<tree string="Vendor Information">
|
||||||
<field name="sequence" widget="handle"/>
|
<field name="sequence" widget="handle"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="delay"/>
|
<field name="product_tmpl_id" string="Product" invisible="context.get('visible_product_tmpl_id', True)"/>
|
||||||
<field name="min_qty"/>
|
<field name="min_qty"/>
|
||||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
<field name="price" string="Price"/>
|
||||||
|
<field name="date_start"/>
|
||||||
|
<field name="date_end"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="product_supplierinfo_type_action" model="ir.actions.act_window">
|
||||||
|
<field name="name">Supplier Pricelist</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="res_model">product.supplierinfo</field>
|
||||||
|
<field name="view_type">form</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
<field name="context">{'visible_product_tmpl_id':False}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|||||||
@@ -5,14 +5,9 @@ access_product_category_user,product.category.user,model_product_category,base.g
|
|||||||
access_product_template_user,product.template.user,model_product_template,base.group_user,1,0,0,0
|
access_product_template_user,product.template.user,model_product_template,base.group_user,1,0,0,0
|
||||||
access_product_packaging_user,product.packaging.user,model_product_packaging,base.group_user,1,0,0,0
|
access_product_packaging_user,product.packaging.user,model_product_packaging,base.group_user,1,0,0,0
|
||||||
access_product_supplierinfo_user,product.supplierinfo.user,model_product_supplierinfo,base.group_user,1,0,0,0
|
access_product_supplierinfo_user,product.supplierinfo.user,model_product_supplierinfo,base.group_user,1,0,0,0
|
||||||
access_pricelist_partnerinfo_user,pricelist.partnerinfo.user,model_pricelist_partnerinfo,base.group_user,1,0,0,0
|
|
||||||
access_product_price_type_user,product.price.type.user,model_product_price_type,base.group_user,1,0,0,0
|
|
||||||
access_product_pricelist_type_user,product.pricelist.type.user,model_product_pricelist_type,,1,0,0,0
|
|
||||||
access_product_pricelist_user,product.pricelist.user,model_product_pricelist,base.group_user,1,0,0,0
|
access_product_pricelist_user,product.pricelist.user,model_product_pricelist,base.group_user,1,0,0,0
|
||||||
access_product_pricelist_version_user,product.pricelist.version.user,model_product_pricelist_version,base.group_user,1,0,0,0
|
|
||||||
access_product_pricelist_item_user,product.pricelist.item.user,model_product_pricelist_item,base.group_user,1,0,0,0
|
access_product_pricelist_item_user,product.pricelist.item.user,model_product_pricelist_item,base.group_user,1,0,0,0
|
||||||
access_product_pricelist_item_sale_manager,product.pricelist.item salemanager,product.model_product_pricelist_item,base.group_sale_manager,1,1,1,1
|
access_product_pricelist_item_sale_manager,product.pricelist.item salemanager,product.model_product_pricelist_item,base.group_sale_manager,1,1,1,1
|
||||||
access_product_pricelist_type_partner_manager,product.pricelist.type partner manager,model_product_pricelist_type,base.group_partner_manager,1,0,0,0
|
|
||||||
access_product_pricelist_partner_manager,product.pricelist partner manager,model_product_pricelist,base.group_partner_manager,1,0,0,0
|
access_product_pricelist_partner_manager,product.pricelist partner manager,model_product_pricelist,base.group_partner_manager,1,0,0,0
|
||||||
access_product_product_employee,product.product employee,model_product_product,base.group_user,1,0,0,0
|
access_product_product_employee,product.product employee,model_product_product,base.group_user,1,0,0,0
|
||||||
access_product_price_history_employee,prices.history employee,model_product_price_history,base.group_user,1,0,0,0
|
access_product_price_history_employee,prices.history employee,model_product_price_history,base.group_user,1,0,0,0
|
||||||
|
|||||||
|
@@ -7,8 +7,13 @@
|
|||||||
<field name="category_id" ref="base.module_category_hidden"/>
|
<field name="category_id" ref="base.module_category_hidden"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="group_purchase_pricelist" model="res.groups">
|
<record id="group_pricelist_item" model="res.groups">
|
||||||
<field name="name">Purchase Pricelists</field>
|
<field name="name">Manage Pricelist Items</field>
|
||||||
|
<field name="category_id" ref="base.module_category_hidden"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="group_product_pricelist" model="res.groups">
|
||||||
|
<field name="name">Pricelists On Product</field>
|
||||||
<field name="category_id" ref="base.module_category_hidden"/>
|
<field name="category_id" ref="base.module_category_hidden"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -62,13 +67,6 @@
|
|||||||
<field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
|
<field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.rule" id="product_pricelist_version_comp_rule">
|
|
||||||
<field name="name">product pricelist version company rule</field>
|
|
||||||
<field name="model_id" ref="model_product_pricelist_version"/>
|
|
||||||
<field name="global" eval="True"/>
|
|
||||||
<field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="ir.rule" id="product_supplierinfo_comp_rule">
|
<record model="ir.rule" id="product_supplierinfo_comp_rule">
|
||||||
<field name="name">product supplierinfo company rule</field>
|
<field name="name">product supplierinfo company rule</field>
|
||||||
<field name="model_id" ref="model_product_supplierinfo"/>
|
<field name="model_id" ref="model_product_supplierinfo"/>
|
||||||
|
|||||||
@@ -51,9 +51,9 @@
|
|||||||
-
|
-
|
||||||
!python {model: product.product}: |
|
!python {model: product.product}: |
|
||||||
from openerp.tools import float_compare
|
from openerp.tools import float_compare
|
||||||
context.update({'quantity':1, 'date': False, 'partner': ref('base.res_partner_4'), 'pricelist': ref("supplier_pricelist")})
|
context.update({'quantity':1, 'date': False, 'partner': ref('base.res_partner_4')})
|
||||||
product = self.browse(cr, uid, ref("product_product_6"), context=context)
|
product = self.browse(cr, uid, ref("product_product_6"), context=context)
|
||||||
assert float_compare(product.price, 792, precision_digits=2) == 0, "Wrong cost price: LCD Monitor."
|
assert float_compare(product.seller_price, 790, precision_digits=2) == 0, "Wrong cost price: LCD Monitor."
|
||||||
-
|
-
|
||||||
I check cost price of LCD Monitor if more than 3 Unit.
|
I check cost price of LCD Monitor if more than 3 Unit.
|
||||||
-
|
-
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
from openerp.tools import float_compare
|
from openerp.tools import float_compare
|
||||||
context.update({'quantity':3})
|
context.update({'quantity':3})
|
||||||
product = self.browse(cr, uid, ref("product_product_6"), context=context)
|
product = self.browse(cr, uid, ref("product_product_6"), context=context)
|
||||||
assert float_compare(product.price, 787, precision_digits=2) == 0, "Wrong cost price: LCD Monitor if more than 3 Unit."
|
assert float_compare(product.seller_price, 785, precision_digits=2) == 0, "Wrong cost price: LCD Monitor if more than 3 Unit."
|
||||||
-
|
-
|
||||||
I print the sale prices report.
|
I print the sale prices report.
|
||||||
-
|
-
|
||||||
|
|||||||
@@ -21,21 +21,19 @@ class TestPricelist(TransactionCase):
|
|||||||
self.public_pricelist_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'list0')[1]
|
self.public_pricelist_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'list0')[1]
|
||||||
self.sale_pricelist_id = self.product_pricelist.create(cr, uid, {
|
self.sale_pricelist_id = self.product_pricelist.create(cr, uid, {
|
||||||
'name': 'Sale pricelist',
|
'name': 'Sale pricelist',
|
||||||
'type': 'sale',
|
'item_ids': [(0, 0, {
|
||||||
'version_id': [(0, 0, {
|
'compute_price': 'formula',
|
||||||
'name': 'v1.0',
|
'base': 'list_price', # based on public price
|
||||||
'items_id': [(0, 0, {
|
'price_discount': 10,
|
||||||
'name': 'Discount 10%',
|
'product_id': self.usb_adapter_id,
|
||||||
'base': 1, # based on public price
|
'applied_on': '0_product_variant',
|
||||||
'price_discount': -0.1,
|
|
||||||
'product_id': self.usb_adapter_id
|
|
||||||
}), (0, 0, {
|
}), (0, 0, {
|
||||||
'name': 'Discount -0.5',
|
'compute_price': 'formula',
|
||||||
'base': 1, # based on public price
|
'base': 'list_price', # based on public price
|
||||||
'price_surcharge': -0.5,
|
'price_surcharge': -0.5,
|
||||||
'product_id': self.datacard_id
|
'product_id': self.datacard_id,
|
||||||
|
'applied_on': '0_product_variant',
|
||||||
})]
|
})]
|
||||||
})]
|
|
||||||
}, context=context)
|
}, context=context)
|
||||||
|
|
||||||
def test_10_discount(self):
|
def test_10_discount(self):
|
||||||
@@ -80,7 +78,6 @@ class TestPricelist(TransactionCase):
|
|||||||
|
|
||||||
# make sure 'tonne' resolves down to 1 'kg'.
|
# make sure 'tonne' resolves down to 1 'kg'.
|
||||||
self.uom.write(cr, uid, tonne, {'rounding': 0.001})
|
self.uom.write(cr, uid, tonne, {'rounding': 0.001})
|
||||||
|
|
||||||
# setup product stored in 'tonnes', with a discounted pricelist for qty > 3 tonnes
|
# setup product stored in 'tonnes', with a discounted pricelist for qty > 3 tonnes
|
||||||
spam_id = self.product_product.copy(cr, uid, self.usb_adapter_id,
|
spam_id = self.product_product.copy(cr, uid, self.usb_adapter_id,
|
||||||
{ 'name': '1 tonne of spam',
|
{ 'name': '1 tonne of spam',
|
||||||
@@ -89,16 +86,15 @@ class TestPricelist(TransactionCase):
|
|||||||
'list_price': tonne_price,
|
'list_price': tonne_price,
|
||||||
'type': 'consu',
|
'type': 'consu',
|
||||||
})
|
})
|
||||||
pricelist_version_id = self.ir_model_data.xmlid_to_res_id(cr, uid, 'product.ver0')
|
self.registry('product.pricelist.item').create(cr, uid, {
|
||||||
self.registry('product.pricelist.item').create(cr, uid,
|
'pricelist_id': self.public_pricelist_id,
|
||||||
{ 'price_version_id': pricelist_version_id,
|
'sequence': 10,
|
||||||
'sequence': 10,
|
'applied_on': '0_product_variant',
|
||||||
'name': '3+ tonnes: -10 EUR discount/t',
|
'compute_price': 'formula',
|
||||||
'base': 1, # based on public price
|
'base': 'list_price', # based on public price
|
||||||
'min_quantity': 3, # min = 3 tonnes
|
'min_quantity': 3, # min = 3 tonnes
|
||||||
'price_surcharge': -10, # -10 EUR / tonne
|
'price_surcharge': -10, # -10 EUR / tonne
|
||||||
'product_id': spam_id,
|
'product_id': spam_id, })
|
||||||
})
|
|
||||||
pricelist_id = self.public_pricelist_id
|
pricelist_id = self.public_pricelist_id
|
||||||
|
|
||||||
def test_unit_price(qty, uom, expected_unit_price):
|
def test_unit_price(qty, uom, expected_unit_price):
|
||||||
|
|||||||
@@ -7,33 +7,30 @@ from openerp.tools.translate import _
|
|||||||
class product_pricelist(osv.osv):
|
class product_pricelist(osv.osv):
|
||||||
_inherit = 'product.pricelist'
|
_inherit = 'product.pricelist'
|
||||||
|
|
||||||
_columns ={
|
_columns = {
|
||||||
'visible_discount': fields.boolean('Visible Discount'),
|
'discount_policy': fields.selection([('with_discount', 'Discount included in the price'), ('without_discount', 'Show discount in the sale order')], string="Discount Policy"),
|
||||||
}
|
|
||||||
_defaults = {
|
|
||||||
'visible_discount': True,
|
|
||||||
}
|
}
|
||||||
|
_defaults = {'discount_policy': 'with_discount'}
|
||||||
|
|
||||||
|
|
||||||
class sale_order_line(osv.osv):
|
class sale_order_line(osv.osv):
|
||||||
_inherit = "sale.order.line"
|
_inherit = "sale.order.line"
|
||||||
|
|
||||||
def get_real_price_currency(self, cr, uid, product_id, res_dict, qty, uom, pricelist, context=None):
|
def _get_real_price_currency(self, cr, uid, product_id, res_dict, qty, uom, pricelist, context=None):
|
||||||
"""Retrieve the price before applying the pricelist"""
|
"""Retrieve the price before applying the pricelist"""
|
||||||
item_obj = self.pool['product.pricelist.item']
|
item_obj = self.pool['product.pricelist.item']
|
||||||
price_type_obj = self.pool['product.price.type']
|
|
||||||
product_obj = self.pool['product.product']
|
product_obj = self.pool['product.product']
|
||||||
field_name = 'list_price'
|
field_name = 'list_price'
|
||||||
|
currency_id = None
|
||||||
if res_dict.get(pricelist):
|
if res_dict.get(pricelist):
|
||||||
rule_id = res_dict[pricelist][1]
|
rule_id = res_dict[pricelist][1]
|
||||||
else:
|
else:
|
||||||
rule_id = False
|
rule_id = False
|
||||||
if rule_id:
|
if rule_id:
|
||||||
item_base = item_obj.browse(cr, uid, rule_id, context=context).base
|
item = item_obj.browse(cr, uid, rule_id, context=context)
|
||||||
if item_base > 0:
|
if item.base == 'standard_price':
|
||||||
price_type = price_type_obj.browse(cr, uid, item_base)
|
field_name = 'standard_price'
|
||||||
field_name = price_type.field
|
currency_id = item.pricelist_id.currency_id.id
|
||||||
currency_id = price_type.currency_id.id
|
|
||||||
|
|
||||||
product = product_obj.browse(cr, uid, product_id, context=context)
|
product = product_obj.browse(cr, uid, product_id, context=context)
|
||||||
if not currency_id:
|
if not currency_id:
|
||||||
@@ -41,7 +38,7 @@ class sale_order_line(osv.osv):
|
|||||||
factor = 1.0
|
factor = 1.0
|
||||||
if uom and uom != product.uom_id.id:
|
if uom and uom != product.uom_id.id:
|
||||||
# the unit price is in a different uom
|
# the unit price is in a different uom
|
||||||
factor = self.pool['product.uom']._compute_qty(cr, uid, uom, 1.0, product.uom_id.id)
|
factor = self.pool['product.uom']._compute_price(cr, uid, uom, 1.0, product.uom_id.id)
|
||||||
return product[field_name] * factor, currency_id
|
return product[field_name] * factor, currency_id
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
@@ -53,8 +50,8 @@ class sale_order_line(osv.osv):
|
|||||||
pricelist_context = dict(context_partner, uom=self.product_uom.id, date=self.order_id.date_order)
|
pricelist_context = dict(context_partner, uom=self.product_uom.id, date=self.order_id.date_order)
|
||||||
list_price = self.order_id.pricelist_id.with_context(pricelist_context).price_rule_get(self.product_id.id, self.product_uom_qty or 1.0, self.order_id.partner_id)
|
list_price = self.order_id.pricelist_id.with_context(pricelist_context).price_rule_get(self.product_id.id, self.product_uom_qty or 1.0, self.order_id.partner_id)
|
||||||
|
|
||||||
new_list_price, currency_id = self.with_context(context_partner).get_real_price_currency(self.product_id.id, list_price, self.product_uom_qty, self.product_uom.id, self.order_id.pricelist_id.id)
|
new_list_price, currency_id = self.with_context(context_partner)._get_real_price_currency(self.product_id.id, list_price, self.product_uom_qty, self.product_uom.id, self.order_id.pricelist_id.id)
|
||||||
if self.order_id.pricelist_id.visible_discount and list_price[self.order_id.pricelist_id.id][0] != 0 and new_list_price != 0:
|
if self.order_id.pricelist_id.discount_policy == 'without_discount' and list_price[self.order_id.pricelist_id.id][0] != 0 and new_list_price != 0:
|
||||||
if self.product_id.company_id and self.order_id.pricelist_id.currency_id.id != self.product_id.company_id.currency_id.id:
|
if self.product_id.company_id and self.order_id.pricelist_id.currency_id.id != self.product_id.company_id.currency_id.id:
|
||||||
# new_list_price is in company's currency while price in pricelist currency
|
# new_list_price is in company's currency while price in pricelist currency
|
||||||
ctx = dict(context_partner, date=self.order_id.date_order)
|
ctx = dict(context_partner, date=self.order_id.date_order)
|
||||||
@@ -81,8 +78,8 @@ class sale_order_line(osv.osv):
|
|||||||
context_partner = dict(self.env.context, partner_id=self.order_id.partner_id.id)
|
context_partner = dict(self.env.context, partner_id=self.order_id.partner_id.id)
|
||||||
pricelist_context = dict(context_partner, uom=self.product_uom.id, date=self.order_id.date_order)
|
pricelist_context = dict(context_partner, uom=self.product_uom.id, date=self.order_id.date_order)
|
||||||
list_price = self.order_id.pricelist_id.with_context(pricelist_context).price_rule_get(self.product_id.id, self.product_uom_qty or 1.0, self.order_id.partner_id)
|
list_price = self.order_id.pricelist_id.with_context(pricelist_context).price_rule_get(self.product_id.id, self.product_uom_qty or 1.0, self.order_id.partner_id)
|
||||||
new_list_price, currency_id = self.with_context(context_partner).get_real_price_currency(self.product_id.id, list_price, self.product_uom_qty, self.product_uom.id, self.order_id.pricelist_id.id)
|
new_list_price, currency_id = self.with_context(context_partner)._get_real_price_currency(self.product_id.id, list_price, self.product_uom_qty, self.product_uom.id, self.order_id.pricelist_id.id)
|
||||||
if self.order_id.pricelist_id.visible_discount and list_price[self.order_id.pricelist_id.id][0] != 0 and new_list_price != 0:
|
if self.order_id.pricelist_id.discount_policy == 'without_discount' and list_price[self.order_id.pricelist_id.id][0] != 0 and new_list_price != 0:
|
||||||
if self.product_id.company_id and self.order_id.pricelist_id.currency_id.id != self.product_id.company_id.currency_id.id:
|
if self.product_id.company_id and self.order_id.pricelist_id.currency_id.id != self.product_id.company_id.currency_id.id:
|
||||||
# new_list_price is in company's currency while price in pricelist currency
|
# new_list_price is in company's currency while price in pricelist currency
|
||||||
ctx = dict(context_partner, date=self.order_id.date_order)
|
ctx = dict(context_partner, date=self.order_id.date_order)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<field name="inherit_id" ref="product.product_pricelist_view_tree"/>
|
<field name="inherit_id" ref="product.product_pricelist_view_tree"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="currency_id" position="before">
|
<field name="currency_id" position="before">
|
||||||
<field name="visible_discount"/>
|
<field name="discount_policy" groups="sale.group_discount_per_so_line"/>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -19,8 +19,11 @@
|
|||||||
<field name="model">product.pricelist</field>
|
<field name="model">product.pricelist</field>
|
||||||
<field name="inherit_id" ref="product.product_pricelist_view"/>
|
<field name="inherit_id" ref="product.product_pricelist_view"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="currency_id" position="before">
|
<field name="active" position="after">
|
||||||
<field name="visible_discount"/>
|
<label for="discount_policy" groups="sale.group_discount_per_so_line"/>
|
||||||
|
<div groups="sale.group_discount_per_so_line">
|
||||||
|
<field name="discount_policy" class="oe_inline" widget="radio" />
|
||||||
|
</div>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -19,15 +19,14 @@ class res_partner(osv.osv):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _commercial_fields(self, cr, uid, context=None):
|
def _commercial_fields(self, cr, uid, context=None):
|
||||||
return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['property_product_pricelist_purchase']
|
return super(res_partner, self)._commercial_fields(cr, uid, context=context)
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'property_product_pricelist_purchase': fields.property(
|
'property_purchase_currency_id': fields.property(
|
||||||
type='many2one',
|
type='many2one',
|
||||||
relation='product.pricelist',
|
relation='res.currency',
|
||||||
domain=[('type','=','purchase')],
|
string="Supplier Currency",
|
||||||
string="Purchase Pricelist",
|
help="This currency will be used, instead of the default one, for purchases from the current partner"),
|
||||||
help="This pricelist will be used, instead of the default one, for purchases from the current partner"),
|
|
||||||
'purchase_order_count': fields.function(_purchase_invoice_count, string='# of Purchase Order', type='integer', multi="count"),
|
'purchase_order_count': fields.function(_purchase_invoice_count, string='# of Purchase Order', type='integer', multi="count"),
|
||||||
'supplier_invoice_count': fields.function(_purchase_invoice_count, string='# Vendor Bills', type='integer', multi="count"),
|
'supplier_invoice_count': fields.function(_purchase_invoice_count, string='# Vendor Bills', type='integer', multi="count"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
<openerp>
|
<openerp>
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<record id="view_partner_property_form" model="ir.ui.view">
|
<record id="view_partner_property_form" model="ir.ui.view">
|
||||||
<field name="name">res.partner.purchase.property.form.inherit</field>
|
<field name="name">res.partner.purchase.property.form.inherit</field>
|
||||||
<field name="model">res.partner</field>
|
<field name="model">res.partner</field>
|
||||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||||
<field name="priority">36</field>
|
<field name="priority">36</field>
|
||||||
<field name="groups_id" eval="[(4, ref('product.group_purchase_pricelist'))]"/>
|
<field name="groups_id" eval="[(4, ref('base.group_multi_currency'))]"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<group name="purchase" position="inside">
|
<group name="purchase" position="inside">
|
||||||
<field name="property_product_pricelist_purchase"/>
|
<field name="property_purchase_currency_id"/>
|
||||||
</group>
|
</group>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="act_res_partner_2_purchase_order" model="ir.actions.act_window">
|
<record id="act_res_partner_2_purchase_order" model="ir.actions.act_window">
|
||||||
<field name="name">RFQs and Purchases</field>
|
<field name="name">RFQs and Purchases</field>
|
||||||
<field name="res_model">purchase.order</field>
|
<field name="res_model">purchase.order</field>
|
||||||
|
|||||||
+48
-91
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
from openerp import SUPERUSER_ID, workflow
|
from openerp import SUPERUSER_ID, workflow
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import time
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
@@ -26,7 +27,7 @@ class purchase_order(osv.osv):
|
|||||||
'amount_total': 0.0,
|
'amount_total': 0.0,
|
||||||
}
|
}
|
||||||
val = val1 = 0.0
|
val = val1 = 0.0
|
||||||
cur = order.pricelist_id.currency_id
|
cur = order.currency_id
|
||||||
for line in order.order_line:
|
for line in order.order_line:
|
||||||
line_price = line_obj._calc_line_base_price(cr, uid, line,
|
line_price = line_obj._calc_line_base_price(cr, uid, line,
|
||||||
context=context)
|
context=context)
|
||||||
@@ -226,7 +227,6 @@ class purchase_order(osv.osv):
|
|||||||
"Otherwise, keep empty to deliver to your own company."
|
"Otherwise, keep empty to deliver to your own company."
|
||||||
),
|
),
|
||||||
'location_id': fields.many2one('stock.location', 'Destination', required=True, domain=[('usage','<>','view')], states=READONLY_STATES),
|
'location_id': fields.many2one('stock.location', 'Destination', required=True, domain=[('usage','<>','view')], states=READONLY_STATES),
|
||||||
'pricelist_id':fields.many2one('product.pricelist', 'Pricelist', required=True, states=READONLY_STATES, help="The pricelist sets the currency used for this purchase order. It also computes the vendor price for the selected products/quantities."),
|
|
||||||
'currency_id': fields.many2one('res.currency','Currency', required=True, states=READONLY_STATES),
|
'currency_id': fields.many2one('res.currency','Currency', required=True, states=READONLY_STATES),
|
||||||
'state': fields.selection(STATE_SELECTION, 'Status', readonly=True,
|
'state': fields.selection(STATE_SELECTION, 'Status', readonly=True,
|
||||||
help="The status of the purchase order or the quotation request. "
|
help="The status of the purchase order or the quotation request. "
|
||||||
@@ -302,7 +302,6 @@ class purchase_order(osv.osv):
|
|||||||
'shipped': 0,
|
'shipped': 0,
|
||||||
'invoice_method': 'order',
|
'invoice_method': 'order',
|
||||||
'invoiced': 0,
|
'invoiced': 0,
|
||||||
'pricelist_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').browse(cr, uid, context['partner_id']).property_product_pricelist_purchase.id,
|
|
||||||
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'purchase.order', context=c),
|
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'purchase.order', context=c),
|
||||||
'journal_id': _get_journal,
|
'journal_id': _get_journal,
|
||||||
'currency_id': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id,
|
'currency_id': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id,
|
||||||
@@ -364,11 +363,6 @@ class purchase_order(osv.osv):
|
|||||||
def button_dummy(self, cr, uid, ids, context=None):
|
def button_dummy(self, cr, uid, ids, context=None):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def onchange_pricelist(self, cr, uid, ids, pricelist_id, context=None):
|
|
||||||
if not pricelist_id:
|
|
||||||
return {}
|
|
||||||
return {'value': {'currency_id': self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context).currency_id.id}}
|
|
||||||
|
|
||||||
#Destination address is used when dropshipping
|
#Destination address is used when dropshipping
|
||||||
def onchange_dest_address_id(self, cr, uid, ids, address_id, context=None):
|
def onchange_dest_address_id(self, cr, uid, ids, address_id, context=None):
|
||||||
if not address_id:
|
if not address_id:
|
||||||
@@ -396,6 +390,7 @@ class purchase_order(osv.osv):
|
|||||||
return {'value': {
|
return {'value': {
|
||||||
'fiscal_position_id': False,
|
'fiscal_position_id': False,
|
||||||
'payment_term_id': False,
|
'payment_term_id': False,
|
||||||
|
'currency_id': self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id.id,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
company_id = self.pool.get('res.users')._get_company(cr, uid, context=context)
|
company_id = self.pool.get('res.users')._get_company(cr, uid, context=context)
|
||||||
@@ -404,9 +399,9 @@ class purchase_order(osv.osv):
|
|||||||
fp = self.pool['account.fiscal.position'].get_fiscal_position(cr, uid, company_id, partner_id, context=context)
|
fp = self.pool['account.fiscal.position'].get_fiscal_position(cr, uid, company_id, partner_id, context=context)
|
||||||
supplier = partner.browse(cr, uid, partner_id, context=context)
|
supplier = partner.browse(cr, uid, partner_id, context=context)
|
||||||
return {'value': {
|
return {'value': {
|
||||||
'pricelist_id': supplier.property_product_pricelist_purchase.id,
|
|
||||||
'fiscal_position_id': fp or supplier.property_account_position_id and supplier.property_account_position_id.id or False,
|
'fiscal_position_id': fp or supplier.property_account_position_id and supplier.property_account_position_id.id or False,
|
||||||
'payment_term_id': supplier.property_supplier_payment_term_id.id or False,
|
'payment_term_id': supplier.property_supplier_payment_term_id.id or False,
|
||||||
|
'currency_id': supplier.property_purchase_currency_id.id or self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id.id
|
||||||
}}
|
}}
|
||||||
|
|
||||||
def invoice_open(self, cr, uid, ids, context=None):
|
def invoice_open(self, cr, uid, ids, context=None):
|
||||||
@@ -941,7 +936,7 @@ class purchase_order(osv.osv):
|
|||||||
|
|
||||||
order_lines_to_move = {}
|
order_lines_to_move = {}
|
||||||
for porder in [order for order in self.browse(cr, uid, ids, context=context) if order.state == 'draft']:
|
for porder in [order for order in self.browse(cr, uid, ids, context=context) if order.state == 'draft']:
|
||||||
order_key = make_key(porder, ('partner_id', 'location_id', 'pricelist_id', 'currency_id'))
|
order_key = make_key(porder, ('partner_id', 'location_id', 'currency_id'))
|
||||||
new_order = new_orders.setdefault(order_key, ({}, []))
|
new_order = new_orders.setdefault(order_key, ({}, []))
|
||||||
new_order[1].append(porder.id)
|
new_order[1].append(porder.id)
|
||||||
order_infos = new_order[0]
|
order_infos = new_order[0]
|
||||||
@@ -955,7 +950,6 @@ class purchase_order(osv.osv):
|
|||||||
'dest_address_id': porder.dest_address_id.id,
|
'dest_address_id': porder.dest_address_id.id,
|
||||||
'picking_type_id': porder.picking_type_id.id,
|
'picking_type_id': porder.picking_type_id.id,
|
||||||
'location_id': porder.location_id.id,
|
'location_id': porder.location_id.id,
|
||||||
'pricelist_id': porder.pricelist_id.id,
|
|
||||||
'currency_id': porder.currency_id.id,
|
'currency_id': porder.currency_id.id,
|
||||||
'state': 'draft',
|
'state': 'draft',
|
||||||
'order_line': {},
|
'order_line': {},
|
||||||
@@ -1050,7 +1044,7 @@ class purchase_order_line(osv.osv):
|
|||||||
context=context)
|
context=context)
|
||||||
line_qty = self._calc_line_quantity(cr, uid, line,
|
line_qty = self._calc_line_quantity(cr, uid, line,
|
||||||
context=context)
|
context=context)
|
||||||
cur = line.order_id.pricelist_id.currency_id
|
cur = line.order_id.currency_id
|
||||||
taxes = line.taxes_id.compute_all(line_price, cur,
|
taxes = line.taxes_id.compute_all(line_price, cur,
|
||||||
line_qty, line.product_id,
|
line_qty, line.product_id,
|
||||||
line.order_id.partner_id)
|
line.order_id.partner_id)
|
||||||
@@ -1115,9 +1109,9 @@ class purchase_order_line(osv.osv):
|
|||||||
procurement_obj.write(cr, uid, procurement_ids_to_except, {'state': 'exception'}, context=context)
|
procurement_obj.write(cr, uid, procurement_ids_to_except, {'state': 'exception'}, context=context)
|
||||||
return super(purchase_order_line, self).unlink(cr, uid, ids, context=context)
|
return super(purchase_order_line, self).unlink(cr, uid, ids, context=context)
|
||||||
|
|
||||||
def onchange_product_uom(self, cr, uid, ids, pricelist_id, product_id, qty, uom_id,
|
def onchange_product_uom(self, cr, uid, ids, product_id, qty, uom_id,
|
||||||
partner_id, date_order=False, fiscal_position_id=False, date_planned=False,
|
partner_id, date_order=False, fiscal_position_id=False, date_planned=False,
|
||||||
name=False, price_unit=False, state='draft', context=None):
|
name=False, price_unit=False, state='draft', currency_id=False, context=None):
|
||||||
"""
|
"""
|
||||||
onchange handler of product_uom.
|
onchange handler of product_uom.
|
||||||
"""
|
"""
|
||||||
@@ -1126,23 +1120,23 @@ class purchase_order_line(osv.osv):
|
|||||||
if not uom_id:
|
if not uom_id:
|
||||||
return {'value': {'price_unit': price_unit or 0.0, 'name': name or '', 'product_uom' : uom_id or False}}
|
return {'value': {'price_unit': price_unit or 0.0, 'name': name or '', 'product_uom' : uom_id or False}}
|
||||||
context = dict(context, purchase_uom_check=True)
|
context = dict(context, purchase_uom_check=True)
|
||||||
return self.onchange_product_id(cr, uid, ids, pricelist_id, product_id, qty, uom_id,
|
return self.onchange_product_id(cr, uid, ids, product_id, qty, uom_id,
|
||||||
partner_id, date_order=date_order, fiscal_position_id=fiscal_position_id, date_planned=date_planned,
|
partner_id, date_order=date_order, fiscal_position_id=fiscal_position_id, date_planned=date_planned,
|
||||||
name=name, price_unit=price_unit, state=state, replace=False, context=context)
|
name=name, price_unit=price_unit, state=state, replace=False, currency_id=currency_id, context=context)
|
||||||
|
|
||||||
def _get_date_planned(self, cr, uid, supplier_info, date_order_str, context=None):
|
def _get_date_planned(self, cr, uid, product, date_order_str, context=None):
|
||||||
"""Return the datetime value to use as Schedule Date (``date_planned``) for
|
"""Return the datetime value to use as Schedule Date (``date_planned``) for
|
||||||
PO Lines that correspond to the given product.supplierinfo,
|
PO Lines that correspond to the given product.supplierinfo,
|
||||||
when ordered at `date_order_str`.
|
when ordered at `date_order_str`.
|
||||||
|
|
||||||
:param browse_record | False supplier_info: product.supplierinfo, used to
|
:param browse_record | False product: product.product, used to
|
||||||
determine delivery delay (if False, default delay = 0)
|
determine delivery delay thanks to the selected seller field (if False, default delay = 0)
|
||||||
:param str date_order_str: date of order field, as a string in
|
:param str date_order_str: date of order field, as a string in
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT
|
DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
:rtype: datetime
|
:rtype: datetime
|
||||||
:return: desired Schedule Date for the PO line
|
:return: desired Schedule Date for the PO line
|
||||||
"""
|
"""
|
||||||
supplier_delay = int(supplier_info.delay) if supplier_info else 0
|
supplier_delay = int(product.seller_delay) if product else 0
|
||||||
return datetime.strptime(date_order_str, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=supplier_delay)
|
return datetime.strptime(date_order_str, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=supplier_delay)
|
||||||
|
|
||||||
def action_cancel(self, cr, uid, ids, context=None):
|
def action_cancel(self, cr, uid, ids, context=None):
|
||||||
@@ -1158,26 +1152,23 @@ class purchase_order_line(osv.osv):
|
|||||||
res = [user for user in group_uom.users if user.id == uid]
|
res = [user for user in group_uom.users if user.id == uid]
|
||||||
return len(res) and True or False
|
return len(res) and True or False
|
||||||
|
|
||||||
def onchange_product_id(self, cr, uid, ids, pricelist_id, product_id, qty, uom_id,
|
def onchange_product_id(self, cr, uid, ids, product_id, qty, uom_id,
|
||||||
partner_id, date_order=False, fiscal_position_id=False, date_planned=False,
|
partner_id, date_order=False, fiscal_position_id=False, date_planned=False,
|
||||||
name=False, price_unit=False, state='draft', replace=True, context=None):
|
name=False, price_unit=False, state='draft', replace=True, currency_id=False, context=None):
|
||||||
"""
|
"""
|
||||||
onchange handler of product_id.
|
onchange handler of product_id.
|
||||||
"""
|
"""
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
res = {'value': {'price_unit': price_unit or 0.0, 'name': name or '', 'product_uom' : uom_id or False}}
|
res = {'value': {'price_unit': price_unit or 0.0, 'name': name or '', 'product_uom' : uom_id or False}}
|
||||||
if not product_id:
|
if not product_id:
|
||||||
if not uom_id:
|
if not uom_id:
|
||||||
uom_id = self.default_get(cr, uid, ['product_uom'], context=context).get('product_uom', False)
|
uom_id = self.default_get(cr, uid, ['product_uom'], context=context).get('product_uom', False)
|
||||||
res['value']['product_uom'] = uom_id
|
res['value']['product_uom'] = uom_id
|
||||||
return res
|
return res
|
||||||
|
|
||||||
product_product = self.pool.get('product.product')
|
product_product = self.pool.get('product.product')
|
||||||
product_uom = self.pool.get('product.uom')
|
product_uom = self.pool.get('product.uom')
|
||||||
res_partner = self.pool.get('res.partner')
|
res_partner = self.pool.get('res.partner')
|
||||||
product_pricelist = self.pool.get('product.pricelist')
|
|
||||||
account_fiscal_position = self.pool.get('account.fiscal.position')
|
account_fiscal_position = self.pool.get('account.fiscal.position')
|
||||||
account_tax = self.pool.get('account.tax')
|
account_tax = self.pool.get('account.tax')
|
||||||
|
|
||||||
@@ -1189,10 +1180,14 @@ class purchase_order_line(osv.osv):
|
|||||||
|
|
||||||
# - determine name and notes based on product in partner lang.
|
# - determine name and notes based on product in partner lang.
|
||||||
context_partner = context.copy()
|
context_partner = context.copy()
|
||||||
|
context_partner.update({'partner': partner_id, 'quantity': qty})
|
||||||
if partner_id:
|
if partner_id:
|
||||||
lang = res_partner.browse(cr, uid, partner_id).lang
|
lang = res_partner.browse(cr, uid, partner_id).lang
|
||||||
context_partner.update( {'lang': lang, 'partner_id': partner_id} )
|
context_partner.update({'lang': lang, 'partner_id': partner_id})
|
||||||
product = product_product.browse(cr, uid, product_id, context=context_partner)
|
product = product_product.browse(cr, uid, product_id, context=context_partner)
|
||||||
|
price = product.seller_price
|
||||||
|
if product.selected_seller_id.currency_id.id != currency_id:
|
||||||
|
price = self.pool['res.currency'].compute(cr, uid, product.selected_seller_id.currency_id.id, currency_id, price, context=dict(context or {}, date=date_order))
|
||||||
if replace:
|
if replace:
|
||||||
#call name_get() with partner in the context to eventually match name and description in the seller_ids field
|
#call name_get() with partner in the context to eventually match name and description in the seller_ids field
|
||||||
dummy, name = product_product.name_get(cr, uid, product_id, context=context_partner)[0]
|
dummy, name = product_product.name_get(cr, uid, product_id, context=context_partner)[0]
|
||||||
@@ -1208,7 +1203,8 @@ class purchase_order_line(osv.osv):
|
|||||||
if not uom_id:
|
if not uom_id:
|
||||||
uom_id = product_uom_po_id
|
uom_id = product_uom_po_id
|
||||||
|
|
||||||
if product.uom_id.category_id.id != product_uom.browse(cr, uid, uom_id, context=context).category_id.id:
|
uom = product_uom.browse(cr, uid, uom_id, context=context)
|
||||||
|
if product.uom_id.category_id.id != uom.category_id.id:
|
||||||
if context.get('purchase_uom_check') and self._check_product_uom_group(cr, uid, context=context):
|
if context.get('purchase_uom_check') and self._check_product_uom_group(cr, uid, context=context):
|
||||||
res['warning'] = {'title': _('Warning!'), 'message': _('Selected Unit of Measure does not belong to the same category as the product Unit of Measure.')}
|
res['warning'] = {'title': _('Warning!'), 'message': _('Selected Unit of Measure does not belong to the same category as the product Unit of Measure.')}
|
||||||
uom_id = product_uom_po_id
|
uom_id = product_uom_po_id
|
||||||
@@ -1218,46 +1214,21 @@ class purchase_order_line(osv.osv):
|
|||||||
# - determine product_qty and date_planned based on seller info
|
# - determine product_qty and date_planned based on seller info
|
||||||
if not date_order:
|
if not date_order:
|
||||||
date_order = fields.datetime.now()
|
date_order = fields.datetime.now()
|
||||||
|
dt = self._get_date_planned(cr, uid, product, date_order, context=context).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
|
||||||
supplierinfo = False
|
|
||||||
precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Product Unit of Measure')
|
|
||||||
for supplier in product.seller_ids:
|
|
||||||
if partner_id and (supplier.name.id == partner_id):
|
|
||||||
supplierinfo = supplier
|
|
||||||
if supplierinfo.product_uom.id != uom_id:
|
|
||||||
res['warning'] = {'title': _('Warning!'), 'message': _('The selected supplier only sells this product by %s') % supplierinfo.product_uom.name }
|
|
||||||
min_qty = product_uom._compute_qty(cr, uid, supplierinfo.product_uom.id, supplierinfo.min_qty, to_uom_id=uom_id)
|
|
||||||
if float_compare(min_qty , qty, precision_digits=precision) == 1: # If the supplier quantity is greater than entered from user, set minimal.
|
|
||||||
if qty:
|
|
||||||
res['warning'] = {'title': _('Warning!'), 'message': _('The selected vendor has a minimal quantity set to %s %s, you should not purchase less.') % (supplierinfo.min_qty, supplierinfo.product_uom.name)}
|
|
||||||
qty = min_qty
|
|
||||||
dt = self._get_date_planned(cr, uid, supplierinfo, date_order, context=context).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
|
||||||
qty = qty or 1.0
|
qty = qty or 1.0
|
||||||
res['value'].update({'date_planned': date_planned or dt})
|
res['value'].update({'date_planned': date_planned or dt})
|
||||||
if qty:
|
if qty:
|
||||||
res['value'].update({'product_qty': qty})
|
res['value'].update({'product_qty': qty})
|
||||||
|
|
||||||
price = price_unit
|
|
||||||
if price_unit is False or price_unit is None:
|
|
||||||
# - determine price_unit and taxes_id
|
|
||||||
if pricelist_id:
|
|
||||||
date_order_str = datetime.strptime(date_order, DEFAULT_SERVER_DATETIME_FORMAT).strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
||||||
price = product_pricelist.price_get(cr, uid, [pricelist_id],
|
|
||||||
product.id, qty or 1.0, partner_id or False, {'uom': uom_id, 'date': date_order_str})[pricelist_id]
|
|
||||||
else:
|
|
||||||
price = product.standard_price
|
|
||||||
|
|
||||||
taxes = account_tax.browse(cr, uid, map(lambda x: x.id, product.supplier_taxes_id))
|
taxes = account_tax.browse(cr, uid, map(lambda x: x.id, product.supplier_taxes_id))
|
||||||
fpos = fiscal_position_id and account_fiscal_position.browse(cr, uid, fiscal_position_id, context=context) or False
|
fpos = fiscal_position_id and account_fiscal_position.browse(cr, uid, fiscal_position_id, context=context) or False
|
||||||
taxes_ids = account_fiscal_position.map_tax(cr, uid, fpos, taxes)
|
taxes_ids = account_fiscal_position.map_tax(cr, uid, fpos, taxes)
|
||||||
price = self.pool['account.tax']._fix_tax_included_price(cr, uid, price, product.supplier_taxes_id, taxes_ids)
|
price = self.pool['account.tax']._fix_tax_included_price(cr, uid, price, product.supplier_taxes_id, taxes_ids)
|
||||||
res['value'].update({'price_unit': price, 'taxes_id': taxes_ids})
|
res['value'].update({'price_unit': price, 'taxes_id': taxes_ids})
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
product_id_change = onchange_product_id
|
product_id_change = onchange_product_id
|
||||||
product_uom_change = onchange_product_uom
|
product_uom_change = onchange_product_uom
|
||||||
|
|
||||||
def action_confirm(self, cr, uid, ids, context=None):
|
def action_confirm(self, cr, uid, ids, context=None):
|
||||||
self.write(cr, uid, ids, {'state': 'confirmed'}, context=context)
|
self.write(cr, uid, ids, {'state': 'confirmed'}, context=context)
|
||||||
@@ -1281,7 +1252,6 @@ class procurement_order(osv.osv):
|
|||||||
def propagate_cancels(self, cr, uid, ids, context=None):
|
def propagate_cancels(self, cr, uid, ids, context=None):
|
||||||
purchase_line_obj = self.pool.get('purchase.order.line')
|
purchase_line_obj = self.pool.get('purchase.order.line')
|
||||||
lines_to_cancel = []
|
lines_to_cancel = []
|
||||||
uom_obj = self.pool.get("product.uom")
|
|
||||||
for procurement in self.browse(cr, uid, ids, context=context):
|
for procurement in self.browse(cr, uid, ids, context=context):
|
||||||
if procurement.rule_id.action == 'buy' and procurement.purchase_line_id:
|
if procurement.rule_id.action == 'buy' and procurement.purchase_line_id:
|
||||||
if procurement.purchase_line_id.state not in ('draft', 'cancel'):
|
if procurement.purchase_line_id.state not in ('draft', 'cancel'):
|
||||||
@@ -1420,24 +1390,8 @@ class procurement_order(osv.osv):
|
|||||||
res = {}
|
res = {}
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
uom_obj = self.pool.get('product.uom')
|
|
||||||
pricelist_obj = self.pool.get('product.pricelist')
|
|
||||||
prod_obj = self.pool.get('product.product')
|
prod_obj = self.pool.get('product.product')
|
||||||
acc_pos_obj = self.pool.get('account.fiscal.position')
|
acc_pos_obj = self.pool.get('account.fiscal.position')
|
||||||
|
|
||||||
pricelist_id = partner.property_product_pricelist_purchase.id
|
|
||||||
prices_qty = []
|
|
||||||
qty = {}
|
|
||||||
|
|
||||||
for procurement in procurements:
|
|
||||||
seller_qty = procurement.product_id.seller_qty if procurement.location_id.usage != 'customer' else 0.0
|
|
||||||
uom_id = procurement.product_id.uom_po_id.id
|
|
||||||
qty[procurement.product_id.id] = uom_obj._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty, uom_id)
|
|
||||||
if seller_qty:
|
|
||||||
qty[procurement.product_id.id] = max(qty[procurement.product_id.id], seller_qty)
|
|
||||||
prices_qty += [(procurement.product_id, qty[procurement.product_id.id], partner)]
|
|
||||||
prices = pricelist_obj.price_get_multi(cr, uid, [pricelist_id], prices_qty)
|
|
||||||
|
|
||||||
#Passing partner_id to context for purchase order line integrity of Line name
|
#Passing partner_id to context for purchase order line integrity of Line name
|
||||||
new_context = context.copy()
|
new_context = context.copy()
|
||||||
new_context.update({'lang': partner.lang, 'partner_id': partner.id})
|
new_context.update({'lang': partner.lang, 'partner_id': partner.id})
|
||||||
@@ -1455,26 +1409,31 @@ class procurement_order(osv.osv):
|
|||||||
name = names_dict[procurement.product_id.id]
|
name = names_dict[procurement.product_id.id]
|
||||||
if procurement.product_id.description_purchase:
|
if procurement.product_id.description_purchase:
|
||||||
name += '\n' + procurement.product_id.description_purchase
|
name += '\n' + procurement.product_id.description_purchase
|
||||||
price = prices[procurement.product_id.id][pricelist_id]
|
date = schedule_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
price = uom_obj._compute_price(cr, uid, procurement.product_uom.id, price, to_uom_id=procurement.product_id.product_tmpl_id.uom_po_id.id)
|
|
||||||
|
|
||||||
values = {
|
values = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'product_qty': qty[procurement.product_id.id],
|
|
||||||
'product_id': procurement.product_id.id,
|
'product_id': procurement.product_id.id,
|
||||||
'product_uom': procurement.product_id.uom_po_id.id,
|
'product_uom': procurement.product_id.uom_po_id.id,
|
||||||
'price_unit': price or 0.0,
|
'date_planned': date,
|
||||||
'date_planned': schedule_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
|
||||||
'taxes_id': [(6, 0, taxes)],
|
'taxes_id': [(6, 0, taxes)],
|
||||||
'procurement_ids': [(4, procurement.id)]
|
'procurement_ids': [(4, procurement.id)]
|
||||||
}
|
}
|
||||||
|
# calculate price/qty for valid vendor
|
||||||
|
qty = self.pool['product.uom']._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty, procurement.product_id.uom_po_id.id)
|
||||||
|
new_context.update({'quantity': qty})
|
||||||
|
supplier = prod_obj.browse(cr, uid, procurement.product_id.id, context=new_context).selected_seller_id
|
||||||
|
price = 0.0
|
||||||
|
if supplier:
|
||||||
|
price = supplier.price
|
||||||
|
purchase_currency = supplier.name.property_purchase_currency_id
|
||||||
|
price = self.pool['res.currency'].compute(cr, uid, supplier.currency_id.id, purchase_currency.id, price, context=dict(context or {}, date=date))
|
||||||
|
values.update({'product_qty': qty, 'price_unit': price})
|
||||||
res[procurement.id] = values
|
res[procurement.id] = values
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _calc_new_qty_price(self, cr, uid, procurement, po_line=None, cancel=False, context=None):
|
def _calc_new_qty_price(self, cr, uid, procurement, po_line=None, cancel=False, context=None):
|
||||||
if not po_line:
|
if not po_line:
|
||||||
po_line = procurement.purchase_line_id
|
po_line = procurement.purchase_line_id
|
||||||
|
|
||||||
uom_obj = self.pool.get('product.uom')
|
uom_obj = self.pool.get('product.uom')
|
||||||
qty = uom_obj._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty,
|
qty = uom_obj._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty,
|
||||||
procurement.product_id.uom_po_id.id)
|
procurement.product_id.uom_po_id.id)
|
||||||
@@ -1490,8 +1449,9 @@ class procurement_order(osv.osv):
|
|||||||
else:
|
else:
|
||||||
supplierinfo_obj = self.pool.get('product.supplierinfo')
|
supplierinfo_obj = self.pool.get('product.supplierinfo')
|
||||||
supplierinfo_ids = supplierinfo_obj.search(cr, uid, [('name', '=', po_line.order_id.partner_id.id), ('product_tmpl_id', '=', po_line.product_id.product_tmpl_id.id)])
|
supplierinfo_ids = supplierinfo_obj.search(cr, uid, [('name', '=', po_line.order_id.partner_id.id), ('product_tmpl_id', '=', po_line.product_id.product_tmpl_id.id)])
|
||||||
supplierinfo_min_qty = supplierinfo_obj.browse(cr, uid, supplierinfo_ids).min_qty
|
if supplierinfo_ids:
|
||||||
|
supplierinfo = supplierinfo_obj.browse(cr, uid, supplierinfo_ids)
|
||||||
|
supplierinfo_min_qty = sorted(supplierinfo, key=lambda x: x['min_qty'])[0].min_qty
|
||||||
if supplierinfo_min_qty == 0.0:
|
if supplierinfo_min_qty == 0.0:
|
||||||
qty += po_line.product_qty
|
qty += po_line.product_qty
|
||||||
else:
|
else:
|
||||||
@@ -1503,10 +1463,8 @@ class procurement_order(osv.osv):
|
|||||||
|
|
||||||
price = po_line.price_unit
|
price = po_line.price_unit
|
||||||
if qty != po_line.product_qty:
|
if qty != po_line.product_qty:
|
||||||
pricelist_obj = self.pool.get('product.pricelist')
|
price = po_line.product_id.seller_price
|
||||||
pricelist_id = po_line.order_id.partner_id.property_product_pricelist_purchase.id
|
price = self.pool['product.uom']._compute_price(cr, uid, procurement.product_uom.id, price, procurement.product_uom.id)
|
||||||
price = pricelist_obj.price_get(cr, uid, [pricelist_id], procurement.product_id.id, qty, po_line.order_id.partner_id.id, {'uom': procurement.product_uom.id})[pricelist_id]
|
|
||||||
|
|
||||||
return qty, price
|
return qty, price
|
||||||
|
|
||||||
def update_origin_po(self, cr, uid, po, proc, context=None):
|
def update_origin_po(self, cr, uid, po, proc, context=None):
|
||||||
@@ -1514,7 +1472,7 @@ class procurement_order(osv.osv):
|
|||||||
|
|
||||||
def _get_grouping_dicts(self, cr, uid, ids, context=None):
|
def _get_grouping_dicts(self, cr, uid, ids, context=None):
|
||||||
"""
|
"""
|
||||||
It will group the procurements according to the pos they should go into. That way, lines going to the same
|
It will group the procurements according to the pos they should go into. That way, lines going to the same
|
||||||
po, can be processed at once.
|
po, can be processed at once.
|
||||||
Returns two dictionaries:
|
Returns two dictionaries:
|
||||||
add_purchase_dicts: key: po value: procs to add to the po
|
add_purchase_dicts: key: po value: procs to add to the po
|
||||||
@@ -1522,20 +1480,21 @@ class procurement_order(osv.osv):
|
|||||||
values: procs to add
|
values: procs to add
|
||||||
"""
|
"""
|
||||||
po_obj = self.pool.get('purchase.order')
|
po_obj = self.pool.get('purchase.order')
|
||||||
|
date = time.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
# Regroup POs
|
# Regroup POs
|
||||||
cr.execute("""
|
cr.execute("""
|
||||||
SELECT psi.name, p.id, pr.id, pr.picking_type_id, p.location_id, p.partner_dest_id, p.company_id, p.group_id,
|
SELECT psi.name, p.id, pr.id, pr.picking_type_id, p.location_id, p.partner_dest_id, p.company_id, p.group_id,
|
||||||
pr.group_propagation_option, pr.group_id, psi.qty
|
pr.group_propagation_option, pr.group_id,psi.qty
|
||||||
FROM procurement_order AS p
|
FROM procurement_order AS p
|
||||||
LEFT JOIN procurement_rule AS pr ON pr.id = p.rule_id
|
LEFT JOIN procurement_rule AS pr ON pr.id = p.rule_id
|
||||||
LEFT JOIN procurement_group AS pg ON p.group_id = pg.id,
|
LEFT JOIN procurement_group AS pg ON p.group_id = pg.id,
|
||||||
product_supplierinfo AS psi, product_product AS pp
|
product_supplierinfo AS psi, product_product AS pp
|
||||||
WHERE
|
WHERE
|
||||||
p.product_id = pp.id AND p.id in %s AND psi.product_tmpl_id = pp.product_tmpl_id
|
p.product_id = pp.id AND p.id in %s AND psi.product_tmpl_id = pp.product_tmpl_id
|
||||||
AND (psi.company_id = p.company_id or psi.company_id IS NULL)
|
AND (psi.company_id = p.company_id or psi.company_id IS NULL) AND ((psi.date_start IS NULL OR psi.date_start<=%s) AND (psi.date_end IS NULL OR psi.date_end>=%s))
|
||||||
ORDER BY psi.sequence,
|
ORDER BY psi.sequence,
|
||||||
psi.name, p.rule_id, p.location_id, p.company_id, p.partner_dest_id, p.group_id
|
psi.name, p.rule_id, p.location_id, p.company_id, p.partner_dest_id, p.group_id
|
||||||
""", (tuple(ids), ))
|
""", (tuple(ids), date, date))
|
||||||
res = cr.fetchall()
|
res = cr.fetchall()
|
||||||
old = False
|
old = False
|
||||||
# A giant dict for grouping lines, ... to do at once
|
# A giant dict for grouping lines, ... to do at once
|
||||||
@@ -1609,8 +1568,6 @@ class procurement_order(osv.osv):
|
|||||||
else:
|
else:
|
||||||
procs_to_create.append(proc)
|
procs_to_create.append(proc)
|
||||||
|
|
||||||
procs = []
|
|
||||||
|
|
||||||
# FIXME: these are not real tracking values, it should be fixed if tracking values for one2many
|
# FIXME: these are not real tracking values, it should be fixed if tracking values for one2many
|
||||||
# are managed
|
# are managed
|
||||||
def format_message(message_description, tracked_values):
|
def format_message(message_description, tracked_values):
|
||||||
@@ -1674,9 +1631,9 @@ class procurement_order(osv.osv):
|
|||||||
'partner_id': create_purchase[0],
|
'partner_id': create_purchase[0],
|
||||||
'location_id': procurement.location_id.id,
|
'location_id': procurement.location_id.id,
|
||||||
'picking_type_id': procurement.rule_id.picking_type_id.id,
|
'picking_type_id': procurement.rule_id.picking_type_id.id,
|
||||||
'pricelist_id': partner.property_product_pricelist_purchase.id,
|
|
||||||
'date_order': purchase_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
'date_order': purchase_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
||||||
'company_id': procurement.company_id.id,
|
'company_id': procurement.company_id.id,
|
||||||
|
'currency_id': partner.property_purchase_currency_id.id or self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id.id,
|
||||||
'fiscal_position_id': fp,
|
'fiscal_position_id': fp,
|
||||||
'payment_term_id': partner.property_supplier_payment_term_id.id,
|
'payment_term_id': partner.property_supplier_payment_term_id.id,
|
||||||
'dest_address_id': procurement.partner_dest_id.id,
|
'dest_address_id': procurement.partner_dest_id.id,
|
||||||
|
|||||||
@@ -17,31 +17,6 @@
|
|||||||
<field name="name">Purchase Order</field>
|
<field name="name">Purchase Order</field>
|
||||||
<field name="object">purchase.order</field>
|
<field name="object">purchase.order</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="pricelist_type_purchase" model="product.pricelist.type">
|
|
||||||
<field name="name">Purchase Pricelist</field>
|
|
||||||
<field name="key">purchase</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="list0" model="product.pricelist">
|
|
||||||
<field name="name">Default Purchase Pricelist</field>
|
|
||||||
<field name="type">purchase</field>
|
|
||||||
</record>
|
|
||||||
<record id="ver0" model="product.pricelist.version">
|
|
||||||
<field name="pricelist_id" ref="list0"/>
|
|
||||||
<field name="name">Default Purchase Pricelist Version</field>
|
|
||||||
</record>
|
|
||||||
<record id="item0" model="product.pricelist.item">
|
|
||||||
<field name="price_version_id" ref="ver0"/>
|
|
||||||
<field name="base" ref="product.standard_price"/>
|
|
||||||
<field name="name">Default Purchase Pricelist Line</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record forcecreate="True" id="property_product_pricelist_purchase" model="ir.property">
|
|
||||||
<field name="name">property_product_pricelist_purchase</field>
|
|
||||||
<field name="fields_id" search="[('model','=','res.partner'),('name','=','property_product_pricelist_purchase')]"/>
|
|
||||||
<field eval="'product.pricelist,'+str(list0)" name="value"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Purchase-related subtypes for messaging / Chatter -->
|
<!-- Purchase-related subtypes for messaging / Chatter -->
|
||||||
<record id="mt_rfq_confirmed" model="mail.message.subtype">
|
<record id="mt_rfq_confirmed" model="mail.message.subtype">
|
||||||
|
|||||||
@@ -13,43 +13,15 @@
|
|||||||
<menuitem id="menu_procurement_management" name="Purchase"
|
<menuitem id="menu_procurement_management" name="Purchase"
|
||||||
parent="base.menu_purchase_root" sequence="1" />
|
parent="base.menu_purchase_root" sequence="1" />
|
||||||
|
|
||||||
<record id="purchase_pricelist_version_action" model="ir.actions.act_window">
|
|
||||||
<field name="name">Pricelist Versions</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">product.pricelist.version</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_id" ref="product.product_pricelist_version_tree_view"/>
|
|
||||||
<field name="domain">[('pricelist_id.type','=','purchase')]</field>
|
|
||||||
<field name="help" type="html">
|
|
||||||
<p class="oe_view_nocontent_create">
|
|
||||||
Click to add a pricelist version.
|
|
||||||
</p><p>
|
|
||||||
There can be more than one version of a pricelist, each of
|
|
||||||
these must be valid during a certain period of time. Some
|
|
||||||
examples of versions: Main Prices, 2010, 2011, Summer Sales,
|
|
||||||
etc.
|
|
||||||
</p>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<menuitem id="menu_purchase_config" name="Configuration" parent="base.menu_purchase_root" sequence="100" groups="group_purchase_manager,base.group_configuration"/>
|
<menuitem id="menu_purchase_config" name="Configuration" parent="base.menu_purchase_root" sequence="100" groups="group_purchase_manager,base.group_configuration"/>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
id="menu_purchase_config_pricelist" name="Pricelists"
|
id="menu_purchase_config_pricelist" name="Pricelists"
|
||||||
parent="menu_purchase_config" sequence="50" groups="product.group_purchase_pricelist"/>
|
parent="menu_purchase_config" sequence="20" groups="base.group_no_one"/>
|
||||||
<menuitem
|
<menuitem
|
||||||
action="product.product_pricelist_action_for_purchase" id="menu_product_pricelist_action2_purchase"
|
action="product.product_supplierinfo_type_action" id="menu_product_pricelist_action2_purchase"
|
||||||
parent="menu_purchase_config_pricelist" sequence="1" groups="product.group_purchase_pricelist" />
|
parent="menu_purchase_config_pricelist" sequence="1" groups="base.group_no_one"/>
|
||||||
|
|
||||||
<menuitem
|
|
||||||
action="product.product_pricelist_action_for_purchase" id="menu_product_pricelist_action2_purchase"
|
|
||||||
parent="menu_purchase_config_pricelist" sequence="1" groups="product.group_purchase_pricelist" />
|
|
||||||
|
|
||||||
<menuitem
|
|
||||||
action="purchase_pricelist_version_action" id="menu_purchase_pricelist_version_action"
|
|
||||||
parent="menu_purchase_config_pricelist" sequence="2" groups="product.group_purchase_pricelist"/>
|
|
||||||
|
|
||||||
<menuitem
|
|
||||||
action="product.product_price_type_action" id="menu_product_pricelist_action2_purchase_type"
|
|
||||||
parent="menu_purchase_config_pricelist" sequence="60" />
|
|
||||||
<menuitem
|
<menuitem
|
||||||
id="menu_product_in_config_purchase" name="Products"
|
id="menu_product_in_config_purchase" name="Products"
|
||||||
parent="menu_purchase_config" sequence="30" groups="base.group_no_one"/>
|
parent="menu_purchase_config" sequence="30" groups="base.group_no_one"/>
|
||||||
@@ -215,7 +187,6 @@
|
|||||||
<group>
|
<group>
|
||||||
<field name="partner_id" on_change="onchange_partner_id(partner_id, context)" context="{'search_default_supplier':1, 'default_supplier':1, 'default_customer':0}" domain="[('supplier','=',True)]"/>
|
<field name="partner_id" on_change="onchange_partner_id(partner_id, context)" context="{'search_default_supplier':1, 'default_supplier':1, 'default_customer':0}" domain="[('supplier','=',True)]"/>
|
||||||
<field name="partner_ref"/>
|
<field name="partner_ref"/>
|
||||||
<field domain="[('type','=','purchase')]" name="pricelist_id" groups="product.group_purchase_pricelist" on_change="onchange_pricelist(pricelist_id, context)"/>
|
|
||||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
<field name="currency_id" groups="base.group_multi_currency"/>
|
||||||
<field name="journal_id" invisible='1'/>
|
<field name="journal_id" invisible='1'/>
|
||||||
</group>
|
</group>
|
||||||
@@ -237,19 +208,19 @@
|
|||||||
<field name="order_line">
|
<field name="order_line">
|
||||||
<tree string="Purchase Order Lines" editable="bottom">
|
<tree string="Purchase Order Lines" editable="bottom">
|
||||||
<field name="product_id"
|
<field name="product_id"
|
||||||
on_change="onchange_product_id(parent.pricelist_id, product_id, 0, False,
|
on_change="onchange_product_id(product_id, 0, False,
|
||||||
parent.partner_id, parent.date_order, parent.fiscal_position_id, date_planned,
|
parent.partner_id, parent.date_order, parent.fiscal_position_id, date_planned,
|
||||||
name, False, parent.state, True, context)"
|
name, False, parent.state, True, parent.currency_id,context)"
|
||||||
context="{'partner_id': parent.partner_id}"/>
|
context="{'partner_id': parent.partner_id}"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="date_planned"/>
|
<field name="date_planned"/>
|
||||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||||
<field name="account_analytic_id" context="{'default_partner_id':parent.partner_id}" groups="purchase.group_analytic_accounting" domain="[('type','not in',('view','template'))]"/>
|
<field name="account_analytic_id" context="{'default_partner_id':parent.partner_id}" groups="purchase.group_analytic_accounting" domain="[('type','not in',('view','template'))]"/>
|
||||||
<field name="product_qty"
|
<field name="product_qty"
|
||||||
on_change="onchange_product_id(parent.pricelist_id, product_id, product_qty,
|
on_change="onchange_product_id(product_id, product_qty,
|
||||||
product_uom, parent.partner_id, parent.date_order, parent.fiscal_position_id,
|
product_uom, parent.partner_id, parent.date_order, parent.fiscal_position_id,
|
||||||
date_planned, name, False, parent.state, False, context)"/>
|
date_planned, name, False, parent.state, False, parent.currency_id, context)"/>
|
||||||
<field name="product_uom" groups="product.group_uom" on_change="onchange_product_uom(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position_id,date_planned,name,False,parent.state,context)"/>
|
<field name="product_uom" groups="product.group_uom" on_change="onchange_product_uom(product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position_id,date_planned,name,False,parent.state,parent.currency_id,context)"/>
|
||||||
<field name="price_unit"/>
|
<field name="price_unit"/>
|
||||||
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use','=','purchase')]"/>
|
<field name="taxes_id" widget="many2many_tags" domain="[('type_tax_use','=','purchase')]"/>
|
||||||
<field name="price_subtotal" widget="monetary"/>
|
<field name="price_subtotal" widget="monetary"/>
|
||||||
@@ -259,18 +230,18 @@
|
|||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="product_id"
|
<field name="product_id"
|
||||||
on_change="onchange_product_id(parent.pricelist_id, product_id, 0, False,
|
on_change="onchange_product_id(product_id, 0, False,
|
||||||
parent.partner_id, parent.date_order, parent.fiscal_position_id, date_planned,
|
parent.partner_id, parent.date_order, parent.fiscal_position_id, date_planned,
|
||||||
name, False, parent.state, True, context)"
|
name, False, parent.state, True, parent.currency_id, context)"
|
||||||
context="{'partner_id': parent.partner_id}"/>
|
context="{'partner_id': parent.partner_id}"/>
|
||||||
<label for="product_qty"/>
|
<label for="product_qty"/>
|
||||||
<div>
|
<div>
|
||||||
<field name="product_qty" class="oe_inline"
|
<field name="product_qty" class="oe_inline"
|
||||||
on_change="onchange_product_id(parent.pricelist_id, product_id, product_qty,
|
on_change="onchange_product_id(product_id, product_qty,
|
||||||
product_uom, parent.partner_id, parent.date_order, parent.fiscal_position_id,
|
product_uom, parent.partner_id, parent.date_order, parent.fiscal_position_id,
|
||||||
date_planned, name, False, parent.state, False, context)"/>
|
date_planned, name, False, parent.state, False, parent.currency_id, context)"/>
|
||||||
<field name="product_uom" groups="product.group_uom" class="oe_inline"
|
<field name="product_uom" groups="product.group_uom" class="oe_inline"
|
||||||
on_change="onchange_product_uom(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position_id,date_planned,name,False,parent.state,context)"/>
|
on_change="onchange_product_uom(product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position_id,date_planned,name,False,parent.state,parent.currency_id,context)"/>
|
||||||
</div>
|
</div>
|
||||||
<field name="price_unit"/>
|
<field name="price_unit"/>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ class purchase_report(osv.osv):
|
|||||||
'picking_type_id': fields.many2one('stock.warehouse', 'Warehouse', readonly=True),
|
'picking_type_id': fields.many2one('stock.warehouse', 'Warehouse', readonly=True),
|
||||||
'location_id': fields.many2one('stock.location', 'Destination', readonly=True),
|
'location_id': fields.many2one('stock.location', 'Destination', readonly=True),
|
||||||
'partner_id':fields.many2one('res.partner', 'Vendor', readonly=True),
|
'partner_id':fields.many2one('res.partner', 'Vendor', readonly=True),
|
||||||
'pricelist_id':fields.many2one('product.pricelist', 'Pricelist', readonly=True),
|
|
||||||
'date_approve':fields.date('Date Approved', readonly=True),
|
'date_approve':fields.date('Date Approved', readonly=True),
|
||||||
'expected_date':fields.date('Expected Date', readonly=True),
|
'expected_date':fields.date('Expected Date', readonly=True),
|
||||||
'validator' : fields.many2one('res.users', 'Validated By', readonly=True),
|
'validator' : fields.many2one('res.users', 'Validated By', readonly=True),
|
||||||
'product_uom' : fields.many2one('product.uom', 'Reference Unit of Measure', required=True),
|
'product_uom' : fields.many2one('product.uom', 'Reference Unit of Measure', required=True),
|
||||||
'company_id':fields.many2one('res.company', 'Company', readonly=True),
|
'company_id':fields.many2one('res.company', 'Company', readonly=True),
|
||||||
|
'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
|
||||||
'user_id':fields.many2one('res.users', 'Responsible', readonly=True),
|
'user_id':fields.many2one('res.users', 'Responsible', readonly=True),
|
||||||
'delay':fields.float('Days to Validate', digits=(16,2), readonly=True),
|
'delay':fields.float('Days to Validate', digits=(16,2), readonly=True),
|
||||||
'delay_pass':fields.float('Days to Deliver', digits=(16,2), readonly=True),
|
'delay_pass':fields.float('Days to Deliver', digits=(16,2), readonly=True),
|
||||||
@@ -68,7 +68,6 @@ class purchase_report(osv.osv):
|
|||||||
s.date_approve,
|
s.date_approve,
|
||||||
s.minimum_planned_date as expected_date,
|
s.minimum_planned_date as expected_date,
|
||||||
s.dest_address_id,
|
s.dest_address_id,
|
||||||
s.pricelist_id,
|
|
||||||
s.validator,
|
s.validator,
|
||||||
spt.warehouse_id as picking_type_id,
|
spt.warehouse_id as picking_type_id,
|
||||||
s.partner_id as partner_id,
|
s.partner_id as partner_id,
|
||||||
@@ -115,7 +114,6 @@ class purchase_report(osv.osv):
|
|||||||
l.date_planned,
|
l.date_planned,
|
||||||
l.product_uom,
|
l.product_uom,
|
||||||
s.minimum_planned_date,
|
s.minimum_planned_date,
|
||||||
s.pricelist_id,
|
|
||||||
s.validator,
|
s.validator,
|
||||||
s.dest_address_id,
|
s.dest_address_id,
|
||||||
s.fiscal_position_id,
|
s.fiscal_position_id,
|
||||||
|
|||||||
@@ -20,13 +20,6 @@ class purchase_config_settings(osv.osv_memory):
|
|||||||
('picking', 'Control vendor bill on incoming shipments'),
|
('picking', 'Control vendor bill on incoming shipments'),
|
||||||
('order', 'Control vendor bill on a pregenerated draft invoice'),
|
('order', 'Control vendor bill on a pregenerated draft invoice'),
|
||||||
], 'Default invoicing control method', required=True, default_model='purchase.order'),
|
], 'Default invoicing control method', required=True, default_model='purchase.order'),
|
||||||
'group_purchase_pricelist':fields.selection([
|
|
||||||
(0, 'Set a fixed cost price on each product'),
|
|
||||||
(1, 'Use pricelists to adapt your price per vendors or products')
|
|
||||||
], "Pricelists",
|
|
||||||
implied_group='product.group_purchase_pricelist',
|
|
||||||
help='Allows to manage different prices based on rules per category of vendor.\n'
|
|
||||||
'Example: 10% for retailers, promotion of 5 EUR on this product, etc.'),
|
|
||||||
'group_uom':fields.selection([
|
'group_uom':fields.selection([
|
||||||
(0, 'Products have only one unit of measure (easier)'),
|
(0, 'Products have only one unit of measure (easier)'),
|
||||||
(1, 'Some products may be sold/puchased in different unit of measures (advanced)')
|
(1, 'Some products may be sold/puchased in different unit of measures (advanced)')
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
</group>
|
</group>
|
||||||
<group string="Purchase Order">
|
<group string="Purchase Order">
|
||||||
<field name="group_product_variant" widget="radio"/>
|
<field name="group_product_variant" widget="radio"/>
|
||||||
<field name="group_purchase_pricelist" widget="radio"/>
|
|
||||||
<field name="group_uom" widget="radio"/>
|
<field name="group_uom" widget="radio"/>
|
||||||
<field name="group_costing_method" widget="radio"/>
|
<field name="group_costing_method" widget="radio"/>
|
||||||
<field name="module_purchase_double_validation" widget="radio"/>
|
<field name="module_purchase_double_validation" widget="radio"/>
|
||||||
|
|||||||
@@ -41,13 +41,7 @@ access_product_category_purchase_manager,product.category purchase_manager,produ
|
|||||||
access_product_template_purchase_manager,product.template purchase_manager,product.model_product_template,purchase.group_purchase_manager,1,1,1,1
|
access_product_template_purchase_manager,product.template purchase_manager,product.model_product_template,purchase.group_purchase_manager,1,1,1,1
|
||||||
access_product_packaging_purchase_manager,product.packaging purchase_manager,product.model_product_packaging,purchase.group_purchase_manager,1,1,1,1
|
access_product_packaging_purchase_manager,product.packaging purchase_manager,product.model_product_packaging,purchase.group_purchase_manager,1,1,1,1
|
||||||
access_product_supplierinfo_purchase_manager,product.supplierinfo purchase_manager,product.model_product_supplierinfo,purchase.group_purchase_manager,1,1,1,1
|
access_product_supplierinfo_purchase_manager,product.supplierinfo purchase_manager,product.model_product_supplierinfo,purchase.group_purchase_manager,1,1,1,1
|
||||||
access_pricelist_partnerinfo_purchase_manager,pricelist.partnerinfo purchase_manager,product.model_pricelist_partnerinfo,purchase.group_purchase_manager,1,1,1,1
|
|
||||||
access_product_price_type_purchase_manager,product.price.type purchase_manager,product.model_product_price_type,purchase.group_purchase_manager,1,1,1,1
|
|
||||||
access_product_pricelist_type_purchase_manager,product.pricelist.type purchase_manager,product.model_product_pricelist_type,purchase.group_purchase_manager,1,1,1,1
|
|
||||||
access_product_pricelist_purchase_manager,product.pricelist purchase_manager,product.model_product_pricelist,purchase.group_purchase_manager,1,1,1,1
|
|
||||||
access_ir_property_group_purchase_manager,ir_property group_purchase_manager,base.model_ir_property,purchase.group_purchase_manager,1,1,1,1
|
|
||||||
access_product_group_res_partner_purchase_manager,res_partner group_purchase_manager,base.model_res_partner,purchase.group_purchase_manager,1,1,1,0
|
access_product_group_res_partner_purchase_manager,res_partner group_purchase_manager,base.model_res_partner,purchase.group_purchase_manager,1,1,1,0
|
||||||
access_product_pricelist_version_purchase_manager,product.pricelist.version purchase_manager,product.model_product_pricelist_version,purchase.group_purchase_manager,1,1,1,1
|
|
||||||
access_product_pricelist_item_purchase_manager,product.pricelist.item purchase_manager,product.model_product_pricelist_item,purchase.group_purchase_manager,1,1,1,1
|
access_product_pricelist_item_purchase_manager,product.pricelist.item purchase_manager,product.model_product_pricelist_item,purchase.group_purchase_manager,1,1,1,1
|
||||||
access_account_account_purchase_manager,account.account purchase manager,account.model_account_account,purchase.group_purchase_manager,1,0,0,0
|
access_account_account_purchase_manager,account.account purchase manager,account.model_account_account,purchase.group_purchase_manager,1,0,0,0
|
||||||
access_account_journal_purchase_manager,account.journal purchase manager,account.model_account_journal,purchase.group_purchase_manager,1,0,0,0
|
access_account_journal_purchase_manager,account.journal purchase manager,account.model_account_journal,purchase.group_purchase_manager,1,0,0,0
|
||||||
|
|||||||
|
@@ -70,8 +70,8 @@ class stock_move(osv.osv):
|
|||||||
|
|
||||||
partner = move.picking_id and move.picking_id.partner_id or False
|
partner = move.picking_id and move.picking_id.partner_id or False
|
||||||
code = self.get_code_from_locs(cr, uid, move, context=context)
|
code = self.get_code_from_locs(cr, uid, move, context=context)
|
||||||
if partner and partner.property_product_pricelist_purchase and code == 'incoming':
|
if partner and code == 'incoming':
|
||||||
currency = partner.property_product_pricelist_purchase.currency_id.id
|
currency = purchase_order.currency_id.id
|
||||||
return partner, uid, currency
|
return partner, uid, currency
|
||||||
return super(stock_move, self)._get_master_data(cr, uid, move, inv_type, context=context)
|
return super(stock_move, self)._get_master_data(cr, uid, move, inv_type, context=context)
|
||||||
|
|
||||||
@@ -105,35 +105,6 @@ class stock_move(osv.osv):
|
|||||||
extra_move_tax[0, move.product_id] = [(6, 0, res['value']['invoice_line_tax_ids'])]
|
extra_move_tax[0, move.product_id] = [(6, 0, res['value']['invoice_line_tax_ids'])]
|
||||||
return (is_extra_move, extra_move_tax)
|
return (is_extra_move, extra_move_tax)
|
||||||
|
|
||||||
|
|
||||||
def attribute_price(self, cr, uid, move, context=None):
|
|
||||||
"""
|
|
||||||
Attribute price to move, important in inter-company moves or receipts with only one partner
|
|
||||||
"""
|
|
||||||
# The method attribute_price of the parent class sets the price to the standard product
|
|
||||||
# price if move.price_unit is zero. We don't want this behavior in the case of a purchase
|
|
||||||
# order since we can purchase goods which are free of charge (e.g. 5 units offered if 100
|
|
||||||
# are purchased).
|
|
||||||
if move.purchase_line_id:
|
|
||||||
return
|
|
||||||
|
|
||||||
code = self.get_code_from_locs(cr, uid, move, context=context)
|
|
||||||
if not move.purchase_line_id and code == 'incoming' and not move.price_unit:
|
|
||||||
partner = move.picking_id and move.picking_id.partner_id or False
|
|
||||||
price = False
|
|
||||||
# If partner given, search price in its purchase pricelist
|
|
||||||
if partner and partner.property_product_pricelist_purchase:
|
|
||||||
pricelist_obj = self.pool.get("product.pricelist")
|
|
||||||
pricelist = partner.property_product_pricelist_purchase.id
|
|
||||||
price = pricelist_obj.price_get(cr, uid, [pricelist],
|
|
||||||
move.product_id.id, move.product_uom_qty, partner.id, {
|
|
||||||
'uom': move.product_uom.id,
|
|
||||||
'date': move.date,
|
|
||||||
})[pricelist]
|
|
||||||
if price:
|
|
||||||
return self.write(cr, uid, [move.id], {'price_unit': price}, context=context)
|
|
||||||
super(stock_move, self).attribute_price(cr, uid, move, context=context)
|
|
||||||
|
|
||||||
def _get_taxes(self, cr, uid, move, context=None):
|
def _get_taxes(self, cr, uid, move, context=None):
|
||||||
if move.origin_returned_move_id.purchase_line_id.taxes_id:
|
if move.origin_returned_move_id.purchase_line_id.taxes_id:
|
||||||
return [tax.id for tax in move.origin_returned_move_id.purchase_line_id.taxes_id]
|
return [tax.id for tax in move.origin_returned_move_id.purchase_line_id.taxes_id]
|
||||||
@@ -141,7 +112,7 @@ class stock_move(osv.osv):
|
|||||||
|
|
||||||
class stock_picking(osv.osv):
|
class stock_picking(osv.osv):
|
||||||
_inherit = 'stock.picking'
|
_inherit = 'stock.picking'
|
||||||
|
|
||||||
def _get_to_invoice(self, cr, uid, ids, name, args, context=None):
|
def _get_to_invoice(self, cr, uid, ids, name, args, context=None):
|
||||||
res = {}
|
res = {}
|
||||||
for picking in self.browse(cr, uid, ids, context=context):
|
for picking in self.browse(cr, uid, ids, context=context):
|
||||||
|
|||||||
@@ -100,7 +100,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_001}:
|
!record {model: purchase.order, id: purchase_order_001}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: 1
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product.product_product_10
|
- product_id: product.product_product_10
|
||||||
product_qty: 1
|
product_qty: 1
|
||||||
|
|||||||
@@ -107,7 +107,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_001_fifo}:
|
!record {model: purchase.order, id: purchase_order_001_fifo}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: 1
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_fifo_anglo_saxon
|
- product_id: product_fifo_anglo_saxon
|
||||||
product_qty: 1
|
product_qty: 1
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_average1}:
|
!record {model: purchase.order, id: purchase_order_average1}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_average_icecream
|
- product_id: product_average_icecream
|
||||||
product_qty: 10.0
|
product_qty: 10.0
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_average2}:
|
!record {model: purchase.order, id: purchase_order_average2}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_average_icecream
|
- product_id: product_average_icecream
|
||||||
product_qty: 30.0
|
product_qty: 30.0
|
||||||
@@ -109,7 +107,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_average3}:
|
!record {model: purchase.order, id: purchase_order_average3}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_average_icecream
|
- product_id: product_average_icecream
|
||||||
product_qty: 500.0
|
product_qty: 500.0
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_variable1}:
|
!record {model: purchase.order, id: purchase_order_variable1}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: 1
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_variable_icecream
|
- product_id: product_variable_icecream
|
||||||
product_qty: 10.0
|
product_qty: 10.0
|
||||||
@@ -33,7 +32,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_variable2}:
|
!record {model: purchase.order, id: purchase_order_variable2}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: 1
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_variable_icecream
|
- product_id: product_variable_icecream
|
||||||
product_qty: 30.0
|
product_qty: 30.0
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_variable3}:
|
!record {model: purchase.order, id: purchase_order_variable3}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: 1
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_variable_icecream
|
- product_id: product_variable_icecream
|
||||||
product_qty: 20.0
|
product_qty: 20.0
|
||||||
|
|||||||
@@ -3,9 +3,6 @@
|
|||||||
-
|
-
|
||||||
!record {model: res.company, id: base.main_company}:
|
!record {model: res.company, id: base.main_company}:
|
||||||
currency_id: base.EUR
|
currency_id: base.EUR
|
||||||
-
|
|
||||||
!record {model: product.pricelist, id: purchase.list0}:
|
|
||||||
currency_id: base.EUR
|
|
||||||
-
|
-
|
||||||
Set a product as using fifo price
|
Set a product as using fifo price
|
||||||
-
|
-
|
||||||
@@ -28,8 +25,8 @@
|
|||||||
-
|
-
|
||||||
!record {model: purchase.order, id: purchase_order_fifo1}:
|
!record {model: purchase.order, id: purchase_order_fifo1}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
|
currency_id: base.EUR
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_fifo_icecream
|
- product_id: product_fifo_icecream
|
||||||
product_qty: 10.0
|
product_qty: 10.0
|
||||||
@@ -62,7 +59,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_fifo2}:
|
!record {model: purchase.order, id: purchase_order_fifo2}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_fifo_icecream
|
- product_id: product_fifo_icecream
|
||||||
product_qty: 30.0
|
product_qty: 30.0
|
||||||
@@ -151,35 +147,20 @@
|
|||||||
-
|
-
|
||||||
We will temporarily change the currency rate on the sixth of June to have the same results all year
|
We will temporarily change the currency rate on the sixth of June to have the same results all year
|
||||||
-
|
-
|
||||||
!record {model: res.currency.rate, id: base.rateUSDbis}:
|
Purchase order in USD
|
||||||
rate: 1.2834
|
-
|
||||||
currency_id: base.USD
|
!record {model: res.currency, id: new_USD}:
|
||||||
name: !eval time.strftime('%Y-06-06')
|
name: new_usd
|
||||||
-
|
rate_ids:
|
||||||
Create new pricelist in usd
|
- rate: 1.2834
|
||||||
-
|
name: !eval time.strftime('%Y-%m-%d')
|
||||||
!record {model: product.pricelist, id: supplier_pricelist_usd}:
|
|
||||||
name: Vendor Pricelist
|
|
||||||
type: purchase
|
|
||||||
currency_id: base.USD
|
|
||||||
version_id:
|
|
||||||
- name: v1.0
|
|
||||||
items_id:
|
|
||||||
- name: First version
|
|
||||||
sequence: 1
|
|
||||||
price_min_margin: 2
|
|
||||||
price_max_margin: 5
|
|
||||||
product_id: product_fifo_icecream
|
|
||||||
base: !eval (ref('product.standard_price'))
|
|
||||||
-
|
|
||||||
Purchase order in usd
|
|
||||||
-
|
-
|
||||||
I create a draft Purchase Order for 30000 g at 0.150 USD/g and 10 kg at 150 USD/kg
|
I create a draft Purchase Order for 30000 g at 0.150 USD/g and 10 kg at 150 USD/kg
|
||||||
-
|
-
|
||||||
!record {model: purchase.order, id: purchase_order_fifo_usd}:
|
!record {model: purchase.order, id: purchase_order_fifo_usd}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
|
currency_id: new_USD
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: supplier_pricelist_usd
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_fifo_icecream
|
- product_id: product_fifo_icecream
|
||||||
product_qty: 30000
|
product_qty: 30000
|
||||||
@@ -228,11 +209,11 @@
|
|||||||
picking_obj = self.pool.get('stock.picking').browse(cr, uid, ref("outgoing_fifo_shipment_cur"), context=context)
|
picking_obj = self.pool.get('stock.picking').browse(cr, uid, ref("outgoing_fifo_shipment_cur"), context=context)
|
||||||
picking_obj.do_transfer()
|
picking_obj.do_transfer()
|
||||||
-
|
-
|
||||||
Check rounded price is 102 euro (because last outgoing shipment was made of 19.5kg at 80€ and 30kg at $150 (rate=1.2834)
|
Check rounded price is 102 euro (because last outgoing shipment was made of 19.5kg at 80€ and 30kg at $150 (rate=1.2834)
|
||||||
-
|
-
|
||||||
!python {model: product.product}: |
|
!python {model: product.product}: |
|
||||||
assert round(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price) == 102, "Product price not updated accordingly. %s found instead of 102 (rounded values)" %(round(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price),)
|
assert round(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price) == 102, "Product price not updated accordingly. %s found instead of 102 (rounded values)" %(round(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price),)
|
||||||
-
|
-
|
||||||
Do a delivery of an extra 10 kg
|
Do a delivery of an extra 10 kg
|
||||||
-
|
-
|
||||||
!record {model: stock.picking, id: outgoing_fifo_shipment_ret}:
|
!record {model: stock.picking, id: outgoing_fifo_shipment_ret}:
|
||||||
@@ -266,7 +247,7 @@
|
|||||||
product = self.browse(cr, uid, ref("product_fifo_icecream"))
|
product = self.browse(cr, uid, ref("product_fifo_icecream"))
|
||||||
assert round(product.standard_price) == round(150.0 / 1.2834), "Product price not updated accordingly. %s found instead of %s" %(product.standard_price, round(150.0/1.2834))
|
assert round(product.standard_price) == round(150.0 / 1.2834), "Product price not updated accordingly. %s found instead of %s" %(product.standard_price, round(150.0/1.2834))
|
||||||
assert product.qty_available == 0.0, 'Wrong quantity in stock after first reception'
|
assert product.qty_available == 0.0, 'Wrong quantity in stock after first reception'
|
||||||
-
|
-
|
||||||
Let us create some outs to get negative stock for a new product using the same config
|
Let us create some outs to get negative stock for a new product using the same config
|
||||||
-
|
-
|
||||||
!record {model: product.product, id: product_fifo_negative}:
|
!record {model: product.product, id: product_fifo_negative}:
|
||||||
@@ -340,7 +321,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_fifo_neg}:
|
!record {model: purchase.order, id: purchase_order_fifo_neg}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_fifo_negative
|
- product_id: product_fifo_negative
|
||||||
product_qty: 50.0
|
product_qty: 50.0
|
||||||
@@ -369,7 +349,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_fifo_neg2}:
|
!record {model: purchase.order, id: purchase_order_fifo_neg2}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_fifo_negative
|
- product_id: product_fifo_negative
|
||||||
product_qty: 60.0
|
product_qty: 60.0
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_fiforet1}:
|
!record {model: purchase.order, id: purchase_order_fiforet1}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_fiforet_icecream
|
- product_id: product_fiforet_icecream
|
||||||
product_qty: 10.0
|
product_qty: 10.0
|
||||||
@@ -33,7 +32,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_fiforet2}:
|
!record {model: purchase.order, id: purchase_order_fiforet2}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_fiforet_icecream
|
- product_id: product_fiforet_icecream
|
||||||
product_qty: 30.0
|
product_qty: 30.0
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
for order in self.browse(cr, uid, new_id.keys()):
|
for order in self.browse(cr, uid, new_id.keys()):
|
||||||
assert order.state == 'draft',"New created order state should be in draft"
|
assert order.state == 'draft',"New created order state should be in draft"
|
||||||
assert order.partner_id == order3.partner_id ,"partner is not correspond"
|
assert order.partner_id == order3.partner_id ,"partner is not correspond"
|
||||||
assert order.pricelist_id == order3.pricelist_id,"Price list is not correspond"
|
|
||||||
assert order.location_id == order3.location_id ,"Location is not correspond"
|
assert order.location_id == order3.location_id ,"Location is not correspond"
|
||||||
|
|
||||||
total_new_qty = sum(x.product_qty for x in order.order_line)
|
total_new_qty = sum(x.product_qty for x in order.order_line)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class TestOnchangeProductId(TransactionCase):
|
|||||||
tax_src_id=tax_include_id,
|
tax_src_id=tax_include_id,
|
||||||
tax_dest_id=tax_exclude_id))
|
tax_dest_id=tax_exclude_id))
|
||||||
# import pudb; pudb.set_trace()
|
# import pudb; pudb.set_trace()
|
||||||
res = self.so_line_model.onchange_product_id(cr, uid, [], pricelist, product_id, 1.0, uom_id, partner_id,
|
res = self.so_line_model.onchange_product_id(cr, uid, [], product_id, 1.0, uom_id, partner_id,
|
||||||
fiscal_position_id=fp_id)
|
fiscal_position_id=fp_id)
|
||||||
|
|
||||||
self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price")
|
self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price")
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ class TestPurchase(common.TransactionCase):
|
|||||||
# In order to test I create purchase order and confirmed it.
|
# In order to test I create purchase order and confirmed it.
|
||||||
order = self.env['purchase.order'].create({
|
order = self.env['purchase.order'].create({
|
||||||
'partner_id': partner.id,
|
'partner_id': partner.id,
|
||||||
'location_id': location_id,
|
'location_id': location_id, })
|
||||||
'pricelist_id': 1})
|
|
||||||
self.env['purchase.order.line'].create({
|
self.env['purchase.order.line'].create({
|
||||||
'order_id': order.id,
|
'order_id': order.id,
|
||||||
'product_id': product_id,
|
'product_id': product_id,
|
||||||
|
|||||||
@@ -115,13 +115,11 @@ class purchase_requisition(osv.osv):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def _prepare_purchase_order(self, cr, uid, requisition, supplier, context=None):
|
def _prepare_purchase_order(self, cr, uid, requisition, supplier, context=None):
|
||||||
supplier_pricelist = supplier.property_product_pricelist_purchase
|
|
||||||
return {
|
return {
|
||||||
'origin': requisition.name,
|
'origin': requisition.name,
|
||||||
'date_order': requisition.date_end or fields.datetime.now(),
|
'date_order': requisition.date_end or fields.datetime.now(),
|
||||||
'partner_id': supplier.id,
|
'partner_id': supplier.id,
|
||||||
'pricelist_id': supplier_pricelist.id,
|
'currency_id': requisition.company_id and requisition.company_id.currency_id.id,
|
||||||
'currency_id': supplier_pricelist and supplier_pricelist.currency_id.id or requisition.company_id.currency_id.id,
|
|
||||||
'location_id': requisition.procurement_id and requisition.procurement_id.location_id.id or requisition.picking_type_id.default_location_dest_id.id,
|
'location_id': requisition.procurement_id and requisition.procurement_id.location_id.id or requisition.picking_type_id.default_location_dest_id.id,
|
||||||
'company_id': requisition.company_id.id,
|
'company_id': requisition.company_id.id,
|
||||||
'fiscal_position_id': supplier.property_account_position_id and supplier.property_account_position_id.id or False,
|
'fiscal_position_id': supplier.property_account_position_id and supplier.property_account_position_id.id or False,
|
||||||
@@ -141,9 +139,8 @@ class purchase_requisition(osv.osv):
|
|||||||
ctx['tz'] = requisition.user_id.tz
|
ctx['tz'] = requisition.user_id.tz
|
||||||
date_order = requisition.ordering_date and fields.date.date_to_datetime(self, cr, uid, requisition.ordering_date, context=ctx) or fields.datetime.now()
|
date_order = requisition.ordering_date and fields.date.date_to_datetime(self, cr, uid, requisition.ordering_date, context=ctx) or fields.datetime.now()
|
||||||
qty = product_uom._compute_qty(cr, uid, requisition_line.product_uom_id.id, requisition_line.product_qty, default_uom_po_id)
|
qty = product_uom._compute_qty(cr, uid, requisition_line.product_uom_id.id, requisition_line.product_qty, default_uom_po_id)
|
||||||
supplier_pricelist = supplier.property_product_pricelist_purchase and supplier.property_product_pricelist_purchase.id or False
|
|
||||||
vals = po_line_obj.onchange_product_id(
|
vals = po_line_obj.onchange_product_id(
|
||||||
cr, uid, [], supplier_pricelist, product.id, qty, default_uom_po_id,
|
cr, uid, [], product.id, qty, default_uom_po_id,
|
||||||
supplier.id, date_order=date_order,
|
supplier.id, date_order=date_order,
|
||||||
fiscal_position_id=supplier.property_account_position_id.id,
|
fiscal_position_id=supplier.property_account_position_id.id,
|
||||||
date_planned=requisition_line.schedule_date,
|
date_planned=requisition_line.schedule_date,
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
|
|
||||||
<record id="rfq1" model="purchase.order">
|
<record id="rfq1" model="purchase.order">
|
||||||
<field name="location_id" ref="stock.stock_location_stock"/>
|
<field name="location_id" ref="stock.stock_location_stock"/>
|
||||||
<field name="pricelist_id" ref="purchase.list0"/>
|
|
||||||
<field name="partner_id" ref="base.res_partner_4"/>
|
<field name="partner_id" ref="base.res_partner_4"/>
|
||||||
<field name="requisition_id" ref="requisition1"/>
|
<field name="requisition_id" ref="requisition1"/>
|
||||||
</record>
|
</record>
|
||||||
@@ -46,7 +45,6 @@
|
|||||||
|
|
||||||
<record id="rfq2" model="purchase.order">
|
<record id="rfq2" model="purchase.order">
|
||||||
<field name="location_id" ref="stock.stock_location_stock"/>
|
<field name="location_id" ref="stock.stock_location_stock"/>
|
||||||
<field name="pricelist_id" ref="purchase.list0"/>
|
|
||||||
<field name="partner_id" ref="base.res_partner_1"/>
|
<field name="partner_id" ref="base.res_partner_1"/>
|
||||||
<field name="requisition_id" ref="requisition1"/>
|
<field name="requisition_id" ref="requisition1"/>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -18,13 +18,11 @@ class sale_configuration(osv.TransientModel):
|
|||||||
], "Product Variants",
|
], "Product Variants",
|
||||||
help='Work with product variant allows you to define some variant of the same products, an ease the product management in the ecommerce for example',
|
help='Work with product variant allows you to define some variant of the same products, an ease the product management in the ecommerce for example',
|
||||||
implied_group='product.group_product_variant'),
|
implied_group='product.group_product_variant'),
|
||||||
'group_sale_pricelist':fields.selection([
|
'group_sale_pricelist':fields.boolean("Use pricelists to adapt your price per customers",implied_group='product.group_sale_pricelist',
|
||||||
(0, 'Set a fixed sale price on each product'),
|
|
||||||
(1, 'Use pricelists to adapt your price per customers or products')
|
|
||||||
], "Pricelists",
|
|
||||||
implied_group='product.group_sale_pricelist',
|
|
||||||
help="""Allows to manage different prices based on rules per category of customers.
|
help="""Allows to manage different prices based on rules per category of customers.
|
||||||
Example: 10% for retailers, promotion of 5 EUR on this product, etc."""),
|
Example: 10% for retailers, promotion of 5 EUR on this product, etc."""),
|
||||||
|
'group_pricelist_item':fields.boolean("Show pricelists to customers", implied_group='product.group_pricelist_item'),
|
||||||
|
'group_product_pricelist':fields.boolean("Show pricelists On Products", implied_group='product.group_product_pricelist'),
|
||||||
'group_uom':fields.selection([
|
'group_uom':fields.selection([
|
||||||
(0, 'Products have only one unit of measure (easier)'),
|
(0, 'Products have only one unit of measure (easier)'),
|
||||||
(1, 'Some products may be sold/purchased in different unit of measures (advanced)')
|
(1, 'Some products may be sold/purchased in different unit of measures (advanced)')
|
||||||
@@ -58,6 +56,10 @@ class sale_configuration(osv.TransientModel):
|
|||||||
(0, "Invoicing and shipping addresses are always the same (Example: services companies)"),
|
(0, "Invoicing and shipping addresses are always the same (Example: services companies)"),
|
||||||
(1, 'Have 3 fields on sales orders: customer, invoice address, delivery address')
|
(1, 'Have 3 fields on sales orders: customer, invoice address, delivery address')
|
||||||
], "Customer Addresses", implied_group='sale.group_delivery_invoice_address'),
|
], "Customer Addresses", implied_group='sale.group_delivery_invoice_address'),
|
||||||
|
'sale_pricelist_setting': fields.selection([('fixed', 'A single sale price per product'), ('percentage', 'Different prices per customer segment'), ('formula', 'Advanced pricing based on formula')], required=True,
|
||||||
|
help='Fix Price: all price manage from products sale price.\n'
|
||||||
|
'Different prices per Customer: you can assign price on buying of minimum quantity in products sale tab.\n'
|
||||||
|
'Advanced pricing based on formula: You can have all the rights on pricelist'),
|
||||||
'default_invoice_policy': fields.selection([
|
'default_invoice_policy': fields.selection([
|
||||||
('order', 'Invoice ordered quantities'),
|
('order', 'Invoice ordered quantities'),
|
||||||
('delivery', 'Invoice delivered quantities'),
|
('delivery', 'Invoice delivered quantities'),
|
||||||
@@ -66,12 +68,21 @@ class sale_configuration(osv.TransientModel):
|
|||||||
}
|
}
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
|
'sale_pricelist_setting': 'fixed',
|
||||||
'default_invoice_policy': 'order',
|
'default_invoice_policy': 'order',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def set_sale_defaults(self, cr, uid, ids, context=None):
|
def set_sale_defaults(self, cr, uid, ids, context=None):
|
||||||
return {}
|
sale_price = self.browse(cr, uid, ids, context=context).sale_pricelist_setting
|
||||||
|
res = self.pool.get('ir.values').set_default(cr, uid, 'sale.config.settings', 'sale_pricelist_setting', sale_price)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def onchange_sale_price(self, cr, uid, ids, sale_pricelist_setting, context=None):
|
||||||
|
if sale_pricelist_setting == 'percentage':
|
||||||
|
return {'value': {'group_product_pricelist': True, 'group_sale_pricelist': True, 'group_pricelist_item': False}}
|
||||||
|
if sale_pricelist_setting == 'formula':
|
||||||
|
return {'value': {'group_pricelist_item': True, 'group_sale_pricelist': True, 'group_product_pricelist': False}}
|
||||||
|
return {'value': {'group_pricelist_item': False, 'group_sale_pricelist': False, 'group_product_pricelist': False}}
|
||||||
|
|
||||||
class account_config_settings(osv.osv_memory):
|
class account_config_settings(osv.osv_memory):
|
||||||
_inherit = 'account.config.settings'
|
_inherit = 'account.config.settings'
|
||||||
|
|||||||
@@ -14,13 +14,21 @@
|
|||||||
<field name="default_invoice_policy" widget="radio"/>
|
<field name="default_invoice_policy" widget="radio"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="Quotations & Sales" id="sale">
|
<group string="Quotations & Sales" id="sale">
|
||||||
<field name="group_sale_pricelist" widget="radio"/>
|
|
||||||
<field name="group_sale_delivery_address" widget="radio"/>
|
<field name="group_sale_delivery_address" widget="radio"/>
|
||||||
<field name="group_display_incoterm" widget="radio"/>
|
<field name="group_display_incoterm" widget="radio"/>
|
||||||
<field name="group_discount_per_so_line" widget="radio"/>
|
<field name="group_discount_per_so_line" widget="radio"/>
|
||||||
<field name="module_website_quote" widget="radio"/>
|
<field name="module_website_quote" widget="radio"/>
|
||||||
<field name="module_sale_margin" widget="radio"/>
|
<field name="module_sale_margin" widget="radio"/>
|
||||||
</group>
|
</group>
|
||||||
|
<group name="manage_price">
|
||||||
|
<label for="sale_pricelist_setting" string="Sale Price"/>
|
||||||
|
<div>
|
||||||
|
<field name="sale_pricelist_setting" class="oe_inline" widget="radio" on_change="onchange_sale_price(sale_pricelist_setting)"/>
|
||||||
|
<field name="group_sale_pricelist" class="oe_inline" invisible="1"/>
|
||||||
|
<field name="group_pricelist_item" class="oe_inline" invisible="1"/>
|
||||||
|
<field name="group_product_pricelist" class="oe_inline" invisible="1"/>
|
||||||
|
</div>
|
||||||
|
</group>
|
||||||
</div>
|
</div>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -170,7 +170,7 @@
|
|||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="date_order" invisible="1"/>
|
<field name="date_order" invisible="1"/>
|
||||||
<field domain="[('type','=','sale')]" name="pricelist_id" groups="product.group_sale_pricelist"/>
|
<field name="pricelist_id" groups="product.group_sale_pricelist"/>
|
||||||
<field name="currency_id" invisible="1"/>
|
<field name="currency_id" invisible="1"/>
|
||||||
<field name="validity_date"/>
|
<field name="validity_date"/>
|
||||||
<field name="payment_term_id" options="{'no_create': True}"/>
|
<field name="payment_term_id" options="{'no_create': True}"/>
|
||||||
|
|||||||
@@ -29,12 +29,8 @@ access_product_uom_sale_manager,product.uom salemanager,product.model_product_uo
|
|||||||
access_product_category_sale_manager,product.category salemanager,product.model_product_category,base.group_sale_manager,1,1,1,1
|
access_product_category_sale_manager,product.category salemanager,product.model_product_category,base.group_sale_manager,1,1,1,1
|
||||||
access_product_supplierinfo_user,product.supplierinfo.user,product.model_product_supplierinfo,base.group_sale_salesman,1,0,0,0
|
access_product_supplierinfo_user,product.supplierinfo.user,product.model_product_supplierinfo,base.group_sale_salesman,1,0,0,0
|
||||||
access_product_supplierinfo_sale_manager,product.supplierinfo salemanager,product.model_product_supplierinfo,base.group_sale_manager,1,1,1,1
|
access_product_supplierinfo_sale_manager,product.supplierinfo salemanager,product.model_product_supplierinfo,base.group_sale_manager,1,1,1,1
|
||||||
access_pricelist_partnerinfo_sale_manager,pricelist.partnerinfo salemanager,product.model_pricelist_partnerinfo,base.group_sale_manager,1,1,1,1
|
|
||||||
access_product_price_type_sale_manager,product.price.type salemanager,product.model_product_price_type,base.group_sale_manager,1,1,1,1
|
|
||||||
access_product_pricelist_type_sale_manager,product.pricelist.type salemanager,product.model_product_pricelist_type,base.group_sale_manager,1,1,1,1
|
|
||||||
access_product_pricelist_sale_manager,product.pricelist salemanager,product.model_product_pricelist,base.group_sale_manager,1,1,1,1
|
access_product_pricelist_sale_manager,product.pricelist salemanager,product.model_product_pricelist,base.group_sale_manager,1,1,1,1
|
||||||
access_product_group_res_partner_sale_manager,res_partner group_sale_manager,base.model_res_partner,base.group_sale_manager,1,1,1,0
|
access_product_group_res_partner_sale_manager,res_partner group_sale_manager,base.model_res_partner,base.group_sale_manager,1,1,1,0
|
||||||
access_product_pricelist_version_sale_manager,product.pricelist.version sale_manager,product.model_product_pricelist_version,base.group_sale_manager,1,1,1,1
|
|
||||||
access_account_move_line_salesman,account.move.line invoice,account.model_account_move_line,base.group_sale_salesman,1,0,0,0
|
access_account_move_line_salesman,account.move.line invoice,account.model_account_move_line,base.group_sale_salesman,1,0,0,0
|
||||||
access_sale_order_invoicing_payments,sale.order,model_sale_order,account.group_account_invoice,1,1,0,0
|
access_sale_order_invoicing_payments,sale.order,model_sale_order,account.group_account_invoice,1,1,0,0
|
||||||
access_sale_order_line_invoicing_payments,sale.order.line,model_sale_order_line,account.group_account_invoice,1,1,0,0
|
access_sale_order_line_invoicing_payments,sale.order.line,model_sale_order_line,account.group_account_invoice,1,1,0,0
|
||||||
|
|||||||
|
@@ -60,7 +60,7 @@ class res_partner(osv.Model):
|
|||||||
}
|
}
|
||||||
|
|
||||||
class res_users(osv.Model):
|
class res_users(osv.Model):
|
||||||
_inherit = ['res.users']
|
_inherit = 'res.users'
|
||||||
_columns = {
|
_columns = {
|
||||||
'sale_team_id': fields.many2one('crm.team','Sales Team')
|
'sale_team_id': fields.many2one('crm.team','Sales Team')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,13 +32,9 @@ access_product_template_stock_manager,product.template stock_manager,product.mod
|
|||||||
access_product_product_stock_manager,product.product stock_manager,product.model_product_product,stock.group_stock_manager,1,1,1,1
|
access_product_product_stock_manager,product.product stock_manager,product.model_product_product,stock.group_stock_manager,1,1,1,1
|
||||||
access_product_packaging_stock_manager,product.packaging stock_manager,product.model_product_packaging,stock.group_stock_manager,1,1,1,1
|
access_product_packaging_stock_manager,product.packaging stock_manager,product.model_product_packaging,stock.group_stock_manager,1,1,1,1
|
||||||
access_product_supplierinfo_stock_manager,product.supplierinfo stock_manager,product.model_product_supplierinfo,stock.group_stock_manager,1,1,1,1
|
access_product_supplierinfo_stock_manager,product.supplierinfo stock_manager,product.model_product_supplierinfo,stock.group_stock_manager,1,1,1,1
|
||||||
access_pricelist_partnerinfo_stock_manager,pricelist.partnerinfo stock_manager,product.model_pricelist_partnerinfo,stock.group_stock_manager,1,1,1,1
|
|
||||||
access_product_price_type_stock_manager,product.price.type stock_manager,product.model_product_price_type,stock.group_stock_manager,1,1,1,1
|
|
||||||
access_product_pricelist_type_stock_manager,product.pricelist.type stock_manager,product.model_product_pricelist_type,stock.group_stock_manager,1,1,1,1
|
|
||||||
access_product_pricelist_stock_manager,product.pricelist stock_manager,product.model_product_pricelist,stock.group_stock_manager,1,1,1,1
|
access_product_pricelist_stock_manager,product.pricelist stock_manager,product.model_product_pricelist,stock.group_stock_manager,1,1,1,1
|
||||||
access_ir_property_group_stock_manager,ir_property group_stock_manager,base.model_ir_property,stock.group_stock_manager,1,1,1,1
|
access_ir_property_group_stock_manager,ir_property group_stock_manager,base.model_ir_property,stock.group_stock_manager,1,1,1,1
|
||||||
access_product_group_res_partner_stock_manager,res_partner group_stock_manager,base.model_res_partner,stock.group_stock_manager,1,1,1,0
|
access_product_group_res_partner_stock_manager,res_partner group_stock_manager,base.model_res_partner,stock.group_stock_manager,1,1,1,0
|
||||||
access_product_pricelist_version_stock_manager,product.pricelist.version stock_manager,product.model_product_pricelist_version,stock.group_stock_manager,1,1,1,1
|
|
||||||
access_product_pricelist_item_stock_manager,product.pricelist.item stock_manager,product.model_product_pricelist_item,stock.group_stock_manager,1,1,1,1
|
access_product_pricelist_item_stock_manager,product.pricelist.item stock_manager,product.model_product_pricelist_item,stock.group_stock_manager,1,1,1,1
|
||||||
access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,model_stock_warehouse_orderpoint,stock.group_stock_user,1,0,0,0
|
access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,model_stock_warehouse_orderpoint,stock.group_stock_user,1,0,0,0
|
||||||
access_stock_warehouse_orderpoint_system,stock.warehouse.orderpoint system,model_stock_warehouse_orderpoint,stock.group_stock_manager,1,1,1,1
|
access_stock_warehouse_orderpoint_system,stock.warehouse.orderpoint system,model_stock_warehouse_orderpoint,stock.group_stock_manager,1,1,1,1
|
||||||
|
|||||||
|
@@ -549,7 +549,6 @@ class stock_quant(osv.osv):
|
|||||||
'owner_id': owner_id,
|
'owner_id': owner_id,
|
||||||
'package_id': dest_package_id,
|
'package_id': dest_package_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if move.location_id.usage == 'internal':
|
if move.location_id.usage == 'internal':
|
||||||
#if we were trying to move something from an internal location and reach here (quant creation),
|
#if we were trying to move something from an internal location and reach here (quant creation),
|
||||||
#it means that a negative quant has to be created as well.
|
#it means that a negative quant has to be created as well.
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
-
|
||||||
|
Set the company currency as EURO for the sake of repeatibility
|
||||||
|
-
|
||||||
|
!python {model: res.company}: |
|
||||||
|
self.write(cr, uid, [ref('base.main_company')], {'currency_id':ref('base.EUR')}, context=context)
|
||||||
|
|
||||||
-
|
-
|
||||||
Set product category removal strategy as LIFO
|
Set product category removal strategy as LIFO
|
||||||
-
|
-
|
||||||
@@ -27,7 +33,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_lifo1}:
|
!record {model: purchase.order, id: purchase_order_lifo1}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_lifo_icecream
|
- product_id: product_lifo_icecream
|
||||||
product_qty: 10.0
|
product_qty: 10.0
|
||||||
@@ -40,7 +45,6 @@
|
|||||||
!record {model: purchase.order, id: purchase_order_lifo2}:
|
!record {model: purchase.order, id: purchase_order_lifo2}:
|
||||||
partner_id: base.res_partner_3
|
partner_id: base.res_partner_3
|
||||||
location_id: stock.stock_location_stock
|
location_id: stock.stock_location_stock
|
||||||
pricelist_id: purchase.list0
|
|
||||||
order_line:
|
order_line:
|
||||||
- product_id: product_lifo_icecream
|
- product_id: product_lifo_icecream
|
||||||
product_qty: 30.0
|
product_qty: 30.0
|
||||||
|
|||||||
@@ -190,7 +190,6 @@ class website_sale(http.Controller):
|
|||||||
context['pricelist'] = int(pricelist)
|
context['pricelist'] = int(pricelist)
|
||||||
else:
|
else:
|
||||||
pricelist = pool.get('product.pricelist').browse(cr, uid, context['pricelist'], context)
|
pricelist = pool.get('product.pricelist').browse(cr, uid, context['pricelist'], context)
|
||||||
|
|
||||||
url = "/shop"
|
url = "/shop"
|
||||||
if search:
|
if search:
|
||||||
post["search"] = search
|
post["search"] = search
|
||||||
@@ -227,7 +226,7 @@ class website_sale(http.Controller):
|
|||||||
attributes_ids = attributes_obj.search(cr, uid, [('attribute_line_ids.product_tmpl_id', 'in', product_ids)], context=context)
|
attributes_ids = attributes_obj.search(cr, uid, [('attribute_line_ids.product_tmpl_id', 'in', product_ids)], context=context)
|
||||||
attributes = attributes_obj.browse(cr, uid, attributes_ids, context=context)
|
attributes = attributes_obj.browse(cr, uid, attributes_ids, context=context)
|
||||||
|
|
||||||
from_currency = pool.get('product.price.type')._get_field_currency(cr, uid, 'list_price', context)
|
from_currency = pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id
|
||||||
to_currency = pricelist.currency_id
|
to_currency = pricelist.currency_id
|
||||||
compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
|
compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
|
||||||
|
|
||||||
@@ -277,7 +276,7 @@ class website_sale(http.Controller):
|
|||||||
|
|
||||||
pricelist = self.get_pricelist()
|
pricelist = self.get_pricelist()
|
||||||
|
|
||||||
from_currency = pool.get('product.price.type')._get_field_currency(cr, uid, 'list_price', context)
|
from_currency = pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id
|
||||||
to_currency = pricelist.currency_id
|
to_currency = pricelist.currency_id
|
||||||
compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
|
compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
|
||||||
|
|
||||||
@@ -325,7 +324,7 @@ class website_sale(http.Controller):
|
|||||||
cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
|
cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
|
||||||
order = request.website.sale_get_order()
|
order = request.website.sale_get_order()
|
||||||
if order:
|
if order:
|
||||||
from_currency = pool.get('product.price.type')._get_field_currency(cr, uid, 'list_price', context)
|
from_currency = order.company_id.currency_id
|
||||||
to_currency = order.pricelist_id.currency_id
|
to_currency = order.pricelist_id.currency_id
|
||||||
compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
|
compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -541,11 +541,12 @@ Weight: 31 grams</field>
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="item1" model="product.pricelist.item">
|
<record id="item1" model="product.pricelist.item">
|
||||||
<field name="price_version_id" ref="product.ver0"/>
|
<field name="base">list_price</field>
|
||||||
<field name="base" ref="product.list_price"/>
|
<field name="applied_on">1_product</field>
|
||||||
|
<field name="pricelist_id" ref="product.list0"/>
|
||||||
<field name="product_tmpl_id" ref="product.product_product_4_product_template"/>
|
<field name="product_tmpl_id" ref="product.product_product_4_product_template"/>
|
||||||
<field name="name">Demo Discount</field>
|
<field name="price_discount">20</field>
|
||||||
<field name="price_discount">-0.2000</field>
|
<field name="compute_price">formula</field>
|
||||||
<field name="sequence">1</field>
|
<field name="sequence">1</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -784,34 +785,24 @@ Weight: 31 grams</field>
|
|||||||
|
|
||||||
<record id="list_christmas" model="product.pricelist">
|
<record id="list_christmas" model="product.pricelist">
|
||||||
<field name="name">Christmas Pricelist</field>
|
<field name="name">Christmas Pricelist</field>
|
||||||
<field name="type">sale</field>
|
|
||||||
</record>
|
|
||||||
<record id="ver_christmas" model="product.pricelist.version">
|
|
||||||
<field name="pricelist_id" ref="list_christmas"/>
|
|
||||||
<field name="name">Christmas Pricelist Version</field>
|
|
||||||
</record>
|
</record>
|
||||||
<record id="item_christmas" model="product.pricelist.item">
|
<record id="item_christmas" model="product.pricelist.item">
|
||||||
<field name="price_version_id" ref="ver_christmas"/>
|
<field name="pricelist_id" ref="list_christmas"/>
|
||||||
<field name="base" ref="product.list_price"/>
|
<field name="compute_price">formula</field>
|
||||||
<field name="price_discount">-0.2</field>
|
<field name="base">list_price</field>
|
||||||
|
<field name="price_discount">20</field>
|
||||||
<field name="sequence">10</field>
|
<field name="sequence">10</field>
|
||||||
<field name="name">Christmas Pricelist Line</field>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="list_benelux" model="product.pricelist">
|
<record id="list_benelux" model="product.pricelist">
|
||||||
<field name="name">Benelux Pricelist</field>
|
<field name="name">Benelux Pricelist</field>
|
||||||
<field name="type">sale</field>
|
|
||||||
</record>
|
|
||||||
<record id="ver_benelux" model="product.pricelist.version">
|
|
||||||
<field name="pricelist_id" ref="list_benelux"/>
|
|
||||||
<field name="name">Benelux Pricelist Version</field>
|
|
||||||
</record>
|
</record>
|
||||||
<record id="item_benelux" model="product.pricelist.item">
|
<record id="item_benelux" model="product.pricelist.item">
|
||||||
<field name="price_version_id" ref="ver_benelux"/>
|
<field name="pricelist_id" ref="list_benelux"/>
|
||||||
<field name="base" ref="product.list_price"/>
|
<field name="compute_price">formula</field>
|
||||||
<field name="price_discount">-0.1</field>
|
<field name="base">list_price</field>
|
||||||
|
<field name="price_discount">10</field>
|
||||||
<field name="sequence">10</field>
|
<field name="sequence">10</field>
|
||||||
<field name="name">Benelux Pricelist Line</field>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="benelux" model="res.country.group">
|
<record id="benelux" model="res.country.group">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class product_style(osv.Model):
|
|||||||
class product_pricelist(osv.Model):
|
class product_pricelist(osv.Model):
|
||||||
_inherit = "product.pricelist"
|
_inherit = "product.pricelist"
|
||||||
_columns = {
|
_columns = {
|
||||||
'code': fields.char('Promotional Code'),
|
'code': fields.char('E-commerce Promotional Code'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ access_product_template_public,product.template.public,product.model_product_tem
|
|||||||
access_product_category_public,product.category.public,product.model_product_category,,1,0,0,0
|
access_product_category_public,product.category.public,product.model_product_category,,1,0,0,0
|
||||||
access_product_category_pos_manager,product.public.category manager,model_product_public_category,base.group_sale_manager,1,1,1,1
|
access_product_category_pos_manager,product.public.category manager,model_product_public_category,base.group_sale_manager,1,1,1,1
|
||||||
access_product_public_category_public,product.category.public,model_product_public_category,,1,0,0,0
|
access_product_public_category_public,product.category.public,model_product_public_category,,1,0,0,0
|
||||||
access_product_pricelist_version_public,product.pricelist.version.public,product.model_product_pricelist_version,,1,0,0,0
|
|
||||||
access_product_pricelist_public,product.pricelist.public,product.model_product_pricelist,,1,0,0,0
|
access_product_pricelist_public,product.pricelist.public,product.model_product_pricelist,,1,0,0,0
|
||||||
access_product_pricelist_item_public,product.pricelist.item.public,product.model_product_pricelist_item,,1,0,0,0
|
access_product_pricelist_item_public,product.pricelist.item.public,product.model_product_pricelist_item,,1,0,0,0
|
||||||
access_product_product_price_type_public,product.price.type.public,product.model_product_price_type,,1,0,0,0
|
|
||||||
access_product_style,product.style.public,website_sale.model_product_style,,1,0,0,0
|
access_product_style,product.style.public,website_sale.model_product_style,,1,0,0,0
|
||||||
access_product_supplierinfo,product.supplierinfo.public,product.model_product_supplierinfo,,1,0,0,0
|
access_product_supplierinfo,product.supplierinfo.public,product.model_product_supplierinfo,,1,0,0,0
|
||||||
access_product_attribute_public,product.attribute public,product.model_product_attribute,,1,0,0,0
|
access_product_attribute_public,product.attribute public,product.model_product_attribute,,1,0,0,0
|
||||||
@@ -19,4 +17,3 @@ access_website_pricelist_sale_manager,website_pricelist,model_website_pricelist,
|
|||||||
access_fiscal_position_public,fiscal position public,account.model_account_fiscal_position,base.group_portal,1,0,0,0
|
access_fiscal_position_public,fiscal position public,account.model_account_fiscal_position,base.group_portal,1,0,0,0
|
||||||
access_payment_term,payment term public,account.model_account_payment_term,base.group_portal,1,0,0,0
|
access_payment_term,payment term public,account.model_account_payment_term,base.group_portal,1,0,0,0
|
||||||
access_product_supplierinfo_user,product.supplierinfo.user,product.model_product_supplierinfo,base.group_public,1,0,0,0
|
access_product_supplierinfo_user,product.supplierinfo.user,product.model_product_supplierinfo,base.group_public,1,0,0,0
|
||||||
access_pricelist_partnerinfo_user,pricelist.partnerinfo.user,product.model_pricelist_partnerinfo,base.group_public,1,0,0,0
|
|
||||||
|
@@ -128,7 +128,7 @@
|
|||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="view_id" eval="False"/>
|
<field name="view_id" eval="False"/>
|
||||||
</record>
|
</record>
|
||||||
<menuitem action="website_sale_pricelists_by_website" id="menu_website_sale_pricelists" parent="product.menu_product_pricelist_main" sequence="0" />
|
<menuitem action="website_sale_pricelists_by_website" id="menu_website_sale_pricelists" parent="product.menu_product_pricelist_main" sequence="1" />
|
||||||
|
|
||||||
<!-- Product Public Categories -->
|
<!-- Product Public Categories -->
|
||||||
<record id="website_pricelist_form_view" model="ir.ui.view">
|
<record id="website_pricelist_form_view" model="ir.ui.view">
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class website_sale_options(website_sale):
|
|||||||
|
|
||||||
website_context = kw.get('kwargs', {}).get('context', {})
|
website_context = kw.get('kwargs', {}).get('context', {})
|
||||||
context = dict(context or {}, **website_context)
|
context = dict(context or {}, **website_context)
|
||||||
from_currency = pool.get('product.price.type')._get_field_currency(cr, uid, 'list_price', context)
|
from_currency = pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id
|
||||||
to_currency = pricelist.currency_id
|
to_currency = pricelist.currency_id
|
||||||
compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
|
compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
|
||||||
product = pool['product.product'].browse(cr, uid, int(product_id), context=context)
|
product = pool['product.product'].browse(cr, uid, int(product_id), context=context)
|
||||||
|
|||||||
Reference in New Issue
Block a user