[MERGE] merged the dev2 branch

bzr revid: qdp-launchpad@tinyerp.com-20110117101958-mb28vtb0qckoayn3
This commit is contained in:
qdp-launchpad@tinyerp.com 2011-01-17 11:19:58 +01:00
commit 23606385d4
35 changed files with 493 additions and 326 deletions

View File

@ -96,6 +96,8 @@ def _record_objects(self, cr, uid, data, context):
if '_auto' in dir(obj_pool):
if not obj_pool._auto:
continue
elif '_log_access' not in dir(obj_pool):
search_condition = []
search_ids=obj_pool.search(cr,uid,search_condition)
for s_id in search_ids:
args=(cr.dbname,uid,obj_name,'copy',s_id,{},context)

View File

@ -23,33 +23,15 @@ from osv import fields, osv
from tools.translate import _
from tools import ustr
class report_creator(osv.osv):
class report_result(osv.osv):
"""
Report Creator
"""
_name = "base_report_creator.report"
_name = "base_report_creator_report.result"
_description = "Report"
model_set_id = False
#
# Should request only used fields
#
def export_data(self, cr, uid, ids, fields_to_export, context=None):
if context is None:
context = {}
data_l = self.read(cr, uid, ids, ['sql_query'], context=context)
final_datas = []
#start Loop
for record in data_l:
datas = []
for key in fields_to_export:
value = record.get(key,'')
if isinstance(value, tuple):
datas.append(ustr(value[1]))
else:
datas.append(ustr(value))
final_datas += [datas]
#End Loop
return {'datas': final_datas}
def fields_get(self, cr, user, fields=None, context=None):
"""
@ -64,9 +46,9 @@ class report_creator(osv.osv):
data = context and context.get('report_id', False) or False
if (not context) or 'report_id' not in context:
return super(report_creator, self).fields_get(cr, user, fields, context)
return super(report_result, self).fields_get(cr, user, fields, context)
if data:
report = self.browse(cr, user, data)
report = self.pool.get('base_report_creator.report').browse(cr, user, data,context=context)
models = {}
#Start Loop
for model in report.model_ids:
@ -80,12 +62,8 @@ class report_creator(osv.osv):
i += 1
else:
fields['column_count'] = {'readonly': True, 'type': 'integer', 'string': 'Count', 'size': 64, 'name': 'column_count'}
return fields
#
# Should Call self.fields_get !
#
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
"""
Overrides orm field_view_get.
@ -98,8 +76,8 @@ class report_creator(osv.osv):
data = context and context.get('report_id', False) or False
if (not context) or 'report_id' not in context:
return super(report_creator, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
report = self.browse(cr, user, data)
return super(report_result, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
report = self.pool.get('base_report_creator.report').browse(cr, user, context.get('report_id'), context=context)
models = {}
for model in report.model_ids:
models[model.model] = self.pool.get(model.model).fields_get(cr, user, context=context)
@ -192,31 +170,11 @@ class report_creator(osv.osv):
"""
if context is None:
context = {}
data = context.get('report_id', False)
res = super(report_creator, self).read(cr, user, ids, fields, context, load)
if (not context) or 'report_id' not in context:
return res
wp = ''
for data in res:
if not data.get('sql_query'):
return res
if self.model_set_id:
wp = [self._id_get(cr, user, data, context) + (' in (%s)' % (','.join(map(lambda x: "'" + str(x) + "'", ids))))]
cr.execute(data['sql_query'])
res = cr.dictfetchall()
fields_get = self.fields_get(cr, user, None, context)
for r in res:
for k in r:
r[k] = r[k] or False
field_dict = fields_get.get(k)
field_type = field_dict and field_dict.get('type', False) or False
if field_type and field_type == 'many2one':
if r[k] == False:
continue
related_name = self.pool.get(field_dict.get('relation')).name_get(cr, user, [r[k]], context)[0]
r[k] = related_name
return res
report_id = context.get('active_id', False)
report = self.pool.get('base_report_creator.report').browse(cr, user, context.get('report_id'), context=context)
cr.execute(report.sql_query)
result = cr.dictfetchall()
return result
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
"""
@ -231,9 +189,9 @@ class report_creator(osv.osv):
context_id = context.get('report_id', False)
if (not context) or 'report_id' not in context:
return super(report_creator, self).search(cr, user, args, offset, limit, order, context, count)
return {}
if context_id:
report = self.browse(cr, user, context_id)
report = self.pool.get('base_report_creator.report').browse(cr, user, context_id, context=context)
i = 0
fields = {}
for f in report.field_ids:
@ -254,10 +212,42 @@ class report_creator(osv.osv):
ctx = context or {}
ctx['getid'] = True
sql_query = report.sql_query
cr.execute(sql_query, newargs2)
cr.execute(sql_query) # TODO: FILTER
result = cr.fetchall()
return map(lambda x: x[0], result)
report_result()
class report_creator(osv.osv):
"""
Report Creator
"""
_name = "base_report_creator.report"
_description = "Report"
model_set_id = False
#
# Should request only used fields
#
def export_data(self, cr, uid, ids, fields_to_export, context=None):
if context is None:
context = {}
data_l = self.read(cr, uid, ids, ['sql_query'], context=context)
final_datas = []
#start Loop
for record in data_l:
datas = []
for key in fields_to_export:
value = record.get(key,'')
if isinstance(value, tuple):
datas.append(ustr(value[1]))
else:
datas.append(ustr(value))
final_datas += [datas]
#End Loop
return {'datas': final_datas}
def _path_get(self, cr, uid, models, filter_ids=[]):
"""
@param cr: the current row, from the database cursor,
@ -465,7 +455,7 @@ class report_creator(osv.osv):
'name': rep.name,
'view_type': 'form',
'view_mode': view_mode,
'res_model': 'base_report_creator.report',
'res_model': 'base_report_creator_report.result',
'type': 'ir.actions.act_window',
'context': "{'report_id':%d}" % (rep.id,),
'nodestroy': True,
@ -596,3 +586,4 @@ class report_creator_filter(osv.osv):
}
report_creator_filter()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -41,7 +41,7 @@ appropriate staff, and make sure all future correspondence gets to the right
place.
The CRM module has a email gateway for the synchronisation interface
between mails and OpenERP.
between mails and OpenERP.
Create dashboard for CRM that includes:
* My Leads (list)
* Leads by Stage (graph)
@ -95,6 +95,7 @@ Create dashboard for CRM that includes:
'crm_meeting_view.xml',
'crm_meeting_menu.xml',
'crm_meeting_shortcut_data.xml',
'crm_phonecall_view.xml',
'crm_phonecall_menu.xml',
@ -106,12 +107,12 @@ Create dashboard for CRM that includes:
'report/crm_phonecall_report_view.xml',
'process/crm_configuration_process.xml',
'crm_installer_view.xml',
'crm_installer_view.xml',
'res_partner_view.xml',
'board_crm_view.xml',
'board_crm_statistical_view.xml',
],
'demo_xml': [
'crm_demo.xml',

View File

@ -92,12 +92,6 @@
action="crm_case_categ_meet" parent="menu_meeting_sale"
sequence="1" />
<record id="ir_ui_view_sc_calendar0" model="ir.ui.view_sc">
<field name="name">Meetings</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="crm.menu_crm_case_categ_meet"/>
</record>
<record id="action_view_attendee_form" model="ir.actions.act_window">
<field name="name">Meeting Invitations</field>
<field name="type">ir.actions.act_window</field>

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<record id="ir_ui_view_sc_calendar0" model="ir.ui.view_sc">
<field name="name">Meetings</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="crm.menu_crm_case_categ_meet"/>
</record>
</data>
</openerp>

View File

@ -342,7 +342,7 @@ class mrp_bom(osv.osv):
if context is None:
context = {}
bom_data = self.read(cr, uid, id, [], context=context)
default.update({'name': bom_data['name'] + ' ' + _('Copy')})
default.update({'name': bom_data['name'] + ' ' + _('Copy'), 'bom_id':False})
return super(mrp_bom, self).copy_data(cr, uid, id, default, context=context)
mrp_bom()
@ -444,7 +444,7 @@ class mrp_production(osv.osv):
'bom_id': fields.many2one('mrp.bom', 'Bill of Material', domain=[('bom_id','=',False)]),
'routing_id': fields.many2one('mrp.routing', string='Routing', on_delete='set null', help="The list of operations (list of work centers) to produce the finished product. The routing is mainly used to compute work center costs during operations and to plan future loads on work centers based on production plannification."),
'picking_id': fields.many2one('stock.picking', 'Picking list', readonly=True,
'picking_id': fields.many2one('stock.picking', 'Picking list', readonly=True, ondelete="restrict",
help="This is the internal picking list that brings the finished product to the production plan"),
'move_prod_id': fields.many2one('stock.move', 'Move product', readonly=True),
'move_lines': fields.many2many('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Products to Consume', domain=[('state','not in', ('done', 'cancel'))], states={'done':[('readonly',True)]}),
@ -602,12 +602,18 @@ class mrp_production(osv.osv):
workcenter_line_obj.create(cr, uid, line)
return len(results)
def action_cancel(self, cr, uid, ids):
def action_cancel(self, cr, uid, ids, context=None):
""" Cancels the production order and related stock moves.
@return: True
"""
if context is None:
context = {}
move_obj = self.pool.get('stock.move')
for production in self.browse(cr, uid, ids):
for production in self.browse(cr, uid, ids, context=context):
if production.state == 'confirmed' and production.picking_id.state not in ('draft', 'cancel'):
raise osv.except_osv(
_('Could not cancel manufacturing order !'),
_('You must first cancel related internal picking attached to this manufacturing order.'))
if production.move_created_ids:
move_obj.action_cancel(cr, uid, [x.id for x in production.move_created_ids])
move_obj.action_cancel(cr, uid, [x.id for x in production.move_lines])
@ -664,7 +670,7 @@ class mrp_production(osv.osv):
"""
stock_mov_obj = self.pool.get('stock.move')
production = self.browse(cr, uid, production_id, context=context)
final_product_todo = []
produced_qty = 0
@ -708,9 +714,9 @@ class mrp_production(osv.osv):
if production_mode == 'consume_produce':
# To produce remaining qty of final product
vals = {'state':'confirmed'}
final_product_todo = [x.id for x in production.move_created_ids]
#final_product_todo = [x.id for x in production.move_created_ids]
#stock_mov_obj.write(cr, uid, final_product_todo, vals)
stock_mov_obj.action_confirm(cr, uid, final_product_todo, context)
#stock_mov_obj.action_confirm(cr, uid, final_product_todo, context)
produced_products = {}
for produced_product in production.move_created_ids2:
if produced_product.scrapped:

View File

@ -343,6 +343,54 @@
<field name="date_start"/>
<field name="date_stop"/>
</tree>
<form string="Bill of Material">
<group colspan="4" col="6">
<field name="product_id" on_change="onchange_product_id(product_id, name)" select="1"/>
<field name="name" select="1"/>
<field name="code" select="1" string="Reference" groups="base.group_extended"/>
<newline/>
<field name="product_qty"/>
<field name="product_uom"/>
<field name="routing_id" groups="base.group_extended"/>
<newline/>
<field name="product_uos_qty" groups="product.group_uos" />
<field name="product_uos" groups="product.group_uos"/>
<newline/>
<field name="type" groups="base.group_extended"/>
<field name="company_id" select="1" groups="base.group_multi_company" widget="selection"/>
</group>
<group groups="base.group_extended">
<notebook colspan="4">
<page string="Components">
<field colspan="4" name="bom_lines" nolabel="1" widget="one2many_list">
<tree string="Components" editable="bottom">
<field name="product_id" on_change="onchange_product_id(product_id, name)" select="1"/>
<field name="product_qty"/>
<field name="product_uom"/>
<field name="name" invisible="1"/>
<field name="date_start"/>
<field name="date_stop"/>
</tree>
</field>
</page>
<page string="Revisions" groups="base.group_extended" attrs="{'invisible': [('bom_id','!=',False)]}">
<field colspan="4" name="revision_ids" nolabel="1" widget="one2many_list"/>
</page>
<page string="Properties" groups="base.group_extended">
<field name="position"/>
<field name="active"/>
<field name="sequence"/>
<field name="bom_id"/>
<field name="date_start"/>
<field name="date_stop"/>
<field name="product_rounding"/>
<field name="product_efficiency" groups="base.group_extended"/>
<field colspan="4" name="property_ids" nolabel="2" groups="base.group_extended"/>
</page>
</notebook>
</group>
</form>
</field>
</page>
<page string="Revisions" groups="base.group_extended" attrs="{'invisible': [('bom_id','!=',False)]}">
@ -412,6 +460,28 @@
</tree>
</field>
</record>
<record id="mrp_bom_component_tree_view" model="ir.ui.view">
<field name="name">mrp.bom.component.tree</field>
<field name="model">mrp.bom</field>
<field name="type">tree</field>
<field name="field_parent">child_complete_ids</field>
<field name="arch" type="xml">
<tree string="BoM Structure" colors="blue:method">
<field name="sequence" invisible="1"/>
<field name="name" string="Component Name"/>
<field name="code"/>
<field name="product_id" string="Component Product"/>
<field name="bom_id"/>
<field name="product_qty"/>
<field name="product_uom"/>
<field name="type"/>
<field name="method" groups="base.group_extended"/>
<field name="routing_id" groups="base.group_extended"/>
<field name="date_start" groups="base.group_extended"/>
<field name="date_stop" groups="base.group_extended"/>
</tree>
</field>
</record>
<record id="mrp_bom_form_action" model="ir.actions.act_window">
<field name="name">Bill of Materials</field>
<field name="type">ir.actions.act_window</field>
@ -426,6 +496,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">mrp.bom</field>
<field name="view_type">form</field>
<field name="view_id" ref="mrp_bom_component_tree_view"/>
<field name="domain">[('bom_id','!=',False)]</field>
<field name="help">Bills of materials components are components and sub-products used to create master bills of materials. Use this menu to search in which BoM a specific component is used.</field>
</record>
@ -616,7 +687,6 @@
<field name="product_id" readonly="1"/>
<field name="product_qty" readonly="1" string="Qty"/>
<field name="product_uom" readonly="1" string="UOM"/>
<field name="location_dest_id" readonly="1" string="Destination Loc."/>
<field name="prodlot_id" context="{'product_id': product_id}"/>
<field name="state" invisible="1"/>
<field name="scrapped" invisible="1"/>
@ -630,7 +700,8 @@
<separator colspan="4"/>
<group col="9" colspan="4">
<field name="state"/>
<button name="button_cancel" states="draft,ready,confirmed,in_production,picking_except" string="Cancel" icon="gtk-stop"/>
<button name="button_cancel" states="draft,ready,in_production,picking_except" string="Cancel" icon="gtk-stop"/>
<button name="action_cancel" type="object" states="confirmed" string="Cancel" icon="gtk-stop"/>
<button name="button_confirm" states="draft" string="Confirm Production" icon="gtk-apply"/>
<button name="button_produce" states="ready" string="Start Production" icon="terp-gtk-jump-to-ltr"/>
<button name="%(act_mrp_product_produce)d" states="in_production" string="Produce" icon="gtk-ok" type="action"/>
@ -645,7 +716,6 @@
<field name="product_id" />
<field name="product_qty" string="Qty"/>
<field name="product_uom" string="UOM"/>
<field name="location_id" string="Source Loc." />
<field name="state" invisible="1"/>
<button name="%(stock.action_partial_move_server)d"
string="Partial"
@ -680,7 +750,7 @@
<button name="action_compute" states="draft"
string="Compute Data" type="object"
icon="terp-stock_format-scientific"
colspan="4" />
colspan="2" />
<field colspan="4" name="workcenter_lines" nolabel="1">
<form string="Production Work Centers">
<field colspan="4" name="name"/>
@ -702,7 +772,7 @@
<button name="action_compute" states="draft"
string="Compute Data" type="object"
icon="terp-stock_format-scientific"
colspan="4" />
colspan="2" />
<field colspan="4" name="product_lines" nolabel="1" widget="one2many_list"/>
</page>
<page string="Extra Information">

View File

@ -30,6 +30,11 @@ class StockMove(osv.osv):
_columns = {
'production_id': fields.many2one('mrp.production', 'Production', select=True),
}
def create_chained_picking(self, cr, uid, moves, context=None):
new_moves = super(StockMove, self).create_chained_picking(cr, uid, moves, context=context)
self.write(cr, uid, [x.id for x in new_moves], {'production_id': False}, context=context)
return new_moves
def _action_explode(self, cr, uid, move, context=None):
""" Explodes pickings.

View File

@ -327,6 +327,9 @@ class mrp_repair(osv.osv):
self.write(cr, uid, [o.id], {'state': '2binvoiced'})
else:
self.write(cr, uid, [o.id], {'state': 'confirmed'})
for line in o.operations:
if line.product_id.track_production and not line.prodlot_id:
raise osv.except_osv(_('Warning'), _("Production lot is required for opration line with product '%s'") % (line.product_id.name))
mrp_line_obj.write(cr, uid, [l.id for l in o.operations], {'state': 'confirmed'})
return True
@ -535,6 +538,7 @@ class mrp_repair(osv.osv):
'location_id': move.location_id.id,
'location_dest_id': move.location_dest_id.id,
'tracking_id': False,
'prodlot_id': move.prodlot_id and move.prodlot_id.id or False,
'state': 'done',
})
repair_line_obj.write(cr, uid, [move.id], {'move_id': move_id, 'state': 'done'}, context=context)
@ -661,6 +665,7 @@ class mrp_repair_line(osv.osv, ProductChangeMixin):
'tax_id': fields.many2many('account.tax', 'repair_operation_line_tax', 'repair_operation_line_id', 'tax_id', 'Taxes'),
'product_uom_qty': fields.float('Quantity (UoM)', digits=(16,2), required=True),
'product_uom': fields.many2one('product.uom', 'Product UoM', required=True),
'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number',domain="[('product_id','=',product_id)]"),
'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', readonly=True),
'location_id': fields.many2one('stock.location', 'Source Location', required=True, select=True),
'location_dest_id': fields.many2one('stock.location', 'Dest. Location', required=True, select=True),

View File

@ -49,7 +49,8 @@
<notebook>
<page string="Repair Line">
<field name="name" colspan="4"/>
<field name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id)" colspan="4"/>
<field name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id)"/>
<field name='prodlot_id'/>
<field name="product_uom_qty" string="Qty" />
<field name="product_uom" string="UoM"/>
<field name="price_unit"/>
@ -178,7 +179,7 @@
<field name="arch" type="xml">
<search string="Search Reair Orders">
<group col='4' colspan='4'>
<filter icon="terp-document-new" string="Quotations" domain="[('state','=','draft')]"/>
<filter icon="terp-document-new" string="Quotations" domain="[('state','=','draft')]"/>
<filter icon="terp-check" string="Confirmed" domain="[('state','=','confirmed')]" name="current" />
<filter icon="terp-emblem-important" string="Ready To Repair" domain="[('state','=','ready')]"/>
<separator orientation="vertical"/>
@ -202,7 +203,7 @@
</field>
</record>
<record id="action_repair_order_tree" model="ir.actions.act_window">
<field name="name">Repair Orders</field>
@ -212,7 +213,7 @@
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_repair_order_form_filter"/>
<field name="help">Repair orders allow you to organize your product repairs. In a repair order, you can detail the components you remove, add or replace and record the time you spent on the different operations. The repair order uses the warranty date on the production lot in order to know if whether the repair should be invoiced to the customer or not.</field>
</record>
</record>
<menuitem action="action_repair_order_tree" id="menu_repair_order" parent="mrp.menu_mrp_manufacturing" groups="mrp.group_mrp_user" name="Repair Orders" sequence="50"/>

View File

@ -361,17 +361,22 @@ class procurement_order(osv.osv):
"""
ok = True
if procurement.move_id:
message = False
id = procurement.move_id.id
if not (procurement.move_id.state in ('done','assigned','cancel')):
ok = ok and self.pool.get('stock.move').action_assign(cr, uid, [id])
cr.execute('select count(id) from stock_warehouse_orderpoint where product_id=%s', (procurement.product_id.id,))
if not cr.fetchone()[0]:
cr.execute('update procurement_order set message=%s where id=%s',
(_('Not enough stock and no minimum orderpoint rule defined.'),
procurement.id))
message = _("Procurement '%s' is in exception: not enough stock.") % \
(procurement.name,)
self.log(cr, uid, procurement.id, message)
res = cr.fetchone()[0]
if not res and not ok:
message = _("Not enough stock and no minimum orderpoint rule defined.")
elif not res:
message = _("No minimum orderpoint rule defined.")
elif not ok:
message = _("Not enough stock.")
if message:
self.log(cr, uid, procurement.id, _("Procurement '%s' is in exception: ") % (procurement.name) + message)
cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id))
return ok
def action_produce_assign_service(self, cr, uid, ids, context=None):

View File

@ -53,6 +53,7 @@
'product_data.xml',
'product_report.xml',
'product_view.xml',
'product_shortcut_data.xml',
'pricelist_view.xml',
'partner_view.xml',
'process/product_process.xml'

View File

@ -166,10 +166,9 @@ class product_pricelist(osv.osv):
pricelist_version_ids = pricelist_ids
else:
# all pricelists:
pricelist_version_ids = product_pricelist_version_obj.search(cr, uid, [])
pricelist_version_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context)
pricelist_version_ids = list(set(pricelist_version_ids))
plversions_search_args = [
('pricelist_id', 'in', pricelist_version_ids),
'|',

View File

@ -482,6 +482,19 @@ class product_product(osv.osv):
'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),
'name_template': fields.related('product_tmpl_id', 'name', string="Name", type='char', size=128, store=True),
}
def unlink(self, cr, uid, ids, context=None):
unlink_ids = []
unlink_product_tmpl_ids = []
for product in self.browse(cr, uid, ids, context=context):
tmpl_id = product.product_tmpl_id.id
# Check if the product is last product of this template
other_product_ids = self.search(cr, uid, [('product_tmpl_id', '=', tmpl_id), ('id', '!=', product.id)], context=context)
if not other_product_ids:
unlink_product_tmpl_ids.append(tmpl_id)
unlink_ids.append(product.id)
self.pool.get('product.template').unlink(cr, uid, unlink_product_tmpl_ids, context=context)
return super(product_product, self).unlink(cr, uid, unlink_ids, context=context)
def onchange_uom(self, cursor, user, ids, uom_id,uom_po_id):
if uom_id and uom_po_id:

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="ir_ui_view_sc_product0" model="ir.ui.view_sc">
<field name="name">Products</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="product.menu_products"/>
</record>
</data>
</openerp>

View File

@ -9,7 +9,7 @@
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Product">
<filter string="Services" icon="terp-accessories-archiver" domain="[('type','=','service')]"/>
<filter string="Services" icon="terp-accessories-archiver" domain="[('type','=','service')]"/>
<filter string="Stockable" icon="terp-accessories-archiver" domain="['|',('type','=','product'),('type','=','consu')]"/>
<separator orientation="vertical"/>
<filter string="To Sell" icon="terp-accessories-archiver-minus" domain="[('sale_ok','=',1)]"/>
@ -30,7 +30,7 @@
<separator orientation="vertical"/>
<filter string='Type' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'type'}" />
</group>
</search>
</field>
</record>
@ -101,7 +101,7 @@
</group>
<group colspan="2" col="2" groups="base.group_extended">
<separator string="Weigths" colspan="2"/>
<separator string="Weights" colspan="2"/>
<field digits="(14, 3)" name="volume" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight_net" attrs="{'readonly':[('type','=','service')]}"/>
@ -567,7 +567,7 @@
</group>
<group colspan="2" col="2" groups="base.group_extended">
<separator string="Weigths" colspan="2"/>
<separator string="Weights" colspan="2"/>
<field digits="(14, 3)" name="volume" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight" attrs="{'readonly':[('type','=','service')]}"/>
<field digits="(14, 3)" name="weight_net" attrs="{'readonly':[('type','=','service')]}"/>
@ -635,12 +635,6 @@
<field name="view_type">form</field>
<field name="view_id" ref="product_template_tree_view"/>
</record>
<record id="ir_ui_view_sc_product0" model="ir.ui.view_sc">
<field name="name">Products</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="product.menu_products"/>
</record>
</data>
</openerp>

View File

@ -62,18 +62,18 @@ class product_pricelist(report_sxw.rml_parse):
def _get_pricelist(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['name'])[0]
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['name'], context=self.localcontext)[0]
return pricelist['name']
def _get_currency(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'])[0]
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'], context=self.localcontext)[0]
return pricelist['currency_id'][1]
def _get_currency_symbol(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'])[0]
symbol = pool.get('res.currency').read(self.cr, self.uid, [pricelist['currency_id'][0]], ['symbol'])[0]
pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'], context=self.localcontext)[0]
symbol = pool.get('res.currency').read(self.cr, self.uid, [pricelist['currency_id'][0]], ['symbol'], context=self.localcontext)[0]
return symbol['symbol'] or ''
def _get_categories(self, products,form):
@ -88,13 +88,13 @@ class product_pricelist(report_sxw.rml_parse):
if product.categ_id.id not in cat_ids:
cat_ids.append(product.categ_id.id)
cats = pool.get('product.category').name_get(self.cr, self.uid, cat_ids)
cats = pool.get('product.category').name_get(self.cr, self.uid, cat_ids, context=self.localcontext)
if not cats:
return res
for cat in cats:
product_ids=pool.get('product.product').search(self.cr, self.uid, [('id','in',pro_ids),('categ_id','=',cat[0])])
product_ids=pool.get('product.product').search(self.cr, self.uid, [('id', 'in', pro_ids), ('categ_id', '=', cat[0])], context=self.localcontext)
products = []
for product in pool.get('product.product').read(self.cr, self.uid, product_ids, ['name','code']):
for product in pool.get('product.product').read(self.cr, self.uid, product_ids, ['name', 'code'], context=self.localcontext):
val = {
'id':product['id'],
'name':product['name'],
@ -114,7 +114,7 @@ class product_pricelist(report_sxw.rml_parse):
def _get_price(self,pricelist_id, product_id,qty):
sale_price_digits = self.get_digits(dp='Sale Price')
pool = pooler.get_pool(self.cr.dbname)
price_dict = pool.get('product.pricelist').price_get(self.cr, self.uid, [pricelist_id], product_id,qty)
price_dict = pool.get('product.pricelist').price_get(self.cr, self.uid, [pricelist_id], product_id, qty, context=self.localcontext)
if price_dict[pricelist_id]:
price = self.formatLang(price_dict[pricelist_id], digits=sale_price_digits)
else:

View File

@ -148,7 +148,7 @@ class purchase_order(osv.osv):
STATE_SELECTION = [
('draft', 'Request for Quotation'),
('wait', 'Waiting'),
('confirmed', 'Waiting Supplier Ack'),
('confirmed', 'Waiting Approval'),
('approved', 'Approved'),
('except_picking', 'Shipping Exception'),
('except_invoice', 'Invoice Exception'),
@ -455,6 +455,7 @@ class purchase_order(osv.osv):
'state': 'draft',
'purchase_line_id': order_line.id,
'company_id': order.company_id.id,
'price_unit': order_line.price_unit
})
if order_line.move_dest_id:
self.pool.get('stock.move').write(cr, uid, [order_line.move_dest_id.id], {'location_id':order.location_id.id})
@ -816,4 +817,22 @@ class procurement_order(osv.osv):
procurement_order()
class stock_invoice_onshipping(osv.osv_memory):
_inherit = "stock.invoice.onshipping"
def create_invoice(self, cr, uid, ids, context=None):
if context is None:
context = {}
res = super(stock_invoice_onshipping,self).create_invoice(cr, uid, ids, context=context)
purchase_obj = self.pool.get('purchase.order')
picking_obj = self.pool.get('stock.picking')
for pick_id in res:
pick = picking_obj.browse(cr, uid, pick_id, context=context)
if pick.purchase_id:
purchase_obj.write(cr, uid, [pick.purchase_id.id], {
'invoice_ids': [(4, res[pick_id])]}, context=context)
return res
stock_invoice_onshipping()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -5,19 +5,19 @@
<record id="base.user_demo" model="res.users">
<field eval="[(4, ref('group_purchase_user'))]" name="groups_id"/>
</record>
<!--Resource: purchase.order-->
<record id="order_purchase1" model="purchase.order">
<field name="location_id" ref="stock.stock_location_stock"/>
<field model="product.pricelist" name="pricelist_id" search="[]"/>
<field name="pricelist_id" ref="purchase.list0"/>
<field name="partner_id" ref="base.res_partner_asus"/>
<field name="partner_address_id" ref="base.res_partner_address_tang"/>
</record>
<record id="order_purchase2" model="purchase.order">
<field name="location_id" ref="stock.stock_location_stock"/>
<field model="product.pricelist" name="pricelist_id" search="[]"/>
<field name="pricelist_id" ref="purchase.list0"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="partner_address_id" ref="base.res_partner_address_zen"/>
</record>
@ -48,7 +48,7 @@
<field name="order_id" ref="order_purchase2"/>
<field name="date_planned" eval="time.strftime('%Y/%m/%d')"/>
<field name="name">[PC3] Medium PC</field>
<field name="product_id" ref="product.product_product_pc1"/>
<field name="product_id" ref="product.product_product_pc3"/>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">900</field>
<field name="product_qty">1</field>

View File

@ -15,7 +15,7 @@
<menuitem
id="menu_purchase_config_pricelist" name="Pricelists"
parent="menu_purchase_config_purchase" sequence="50"/>
<menuitem
action="product.product_pricelist_action" id="menu_product_pricelist_action_purhase"
parent="menu_purchase_config_pricelist" sequence="20"/>
@ -32,7 +32,7 @@
<menuitem
id="menu_product_in_config_purchase" name="Product"
parent="menu_purchase_config_purchase" sequence="30"/>
<menuitem
action="product.product_category_action_form" id="menu_product_category_config_purchase"
parent="purchase.menu_product_in_config_purchase" sequence="10"/>
@ -40,7 +40,7 @@
<menuitem
id="menu_purchase_unit_measure_purchase" name="Units of Measure"
parent="purchase.menu_product_in_config_purchase" sequence="20"/>
<menuitem
action="product.product_uom_categ_form_action" id="menu_purchase_uom_categ_form_action"
parent="menu_purchase_unit_measure_purchase" sequence="30"/>
@ -113,10 +113,10 @@
<!--product menu-->
<menuitem id="menu_procurement_management_product" name="Products"
parent="base.menu_purchase_root" sequence="8"/>
<menuitem name="Products by Category" id="menu_product_by_category_purchase_form" action="product.product_category_action"
parent="menu_procurement_management_product" sequence="10"/>
<menuitem name="Products" id="menu_procurement_partner_contact_form" action="product.product_normal_action_puchased"
parent="menu_procurement_management_product"/>
@ -194,7 +194,7 @@
<button name="invoice_ok" states="except_invoice" string="Manually Corrected" icon="gtk-convert"/>
<button name="purchase_confirm" states="draft" string="Convert to Purchase Order" icon="gtk-go-forward"/>
<button name="purchase_appbuyer" states="wait_auth" string="Approve Purchase" icon="gtk-ok"/>
<button name="purchase_approve" states="confirmed" string="Approved by Supplier" icon="gtk-go-forward"/>
<button name="purchase_approve" states="confirmed" string="Approved" icon="gtk-go-forward"/>
<button name="%(report_purchase_order)d" string="Print" states="approved" type="action" icon="gtk-print"/>
</group>
</page>
@ -292,7 +292,7 @@
<field name="search_view_id" ref="view_purchase_order_filter"/>
<field name="help">You can create a request for quotation when you want to buy products to a supplier but the purchase is not confirmed yet. Use also this menu to review requests for quotation created automatically based on your logistic rules (minimum stock, MTO, etc). You can convert the request for quotation into a purchase order once the order is confirmed. If you use the extended interface (from user's preferences), you can select the way to control your supplier invoices: based on the order, based on the receptions or manual encoding.</field>
</record>
<menuitem action="purchase_rfq" id="menu_purchase_rfq"
<menuitem action="purchase_rfq" id="menu_purchase_rfq"
parent="menu_procurement_management"
sequence="6"/>
@ -458,7 +458,7 @@
<field name="name">Purchase Lines Not Invoiced</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">purchase.order.line</field>
<field name="domain">[('state','in',('confirmed','done')), ('invoiced', '=', False)]</field>
<field name="domain">[('order_id.invoice_method','&lt;&gt;','picking'), ('state','in',('confirmed','done')), ('invoiced', '=', False)]</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="purchase_order_line_search"/>

View File

@ -171,7 +171,8 @@
</record>
<menuitem id="base.next_id_73" name="Reporting" parent="base.menu_purchase_root" sequence="8"/>
<menuitem id="base.next_id_73" name="Reporting" parent="base.menu_purchase_root" sequence="8"
groups="purchase.group_purchase_manager"/>
<menuitem action="action_purchase_order_report_all" id="menu_action_purchase_order_report_all" parent="base.next_id_73" sequence="3"/>
<record id="action_stock_move_report_po" model="ir.actions.act_window">

View File

@ -58,6 +58,19 @@ class stock_picking(osv.osv):
'purchase_id': False,
}
def _get_address_invoice(self, cr, uid, picking):
""" Gets invoice address of a partner
@return {'contact': address, 'invoice': address} for invoice
"""
res = super(stock_picking, self)._get_address_invoice(cr, uid, picking)
if picking.purchase_id:
partner_obj = self.pool.get('res.partner')
partner = picking.purchase_id.partner_id or picking.address_id.partner_id
data = partner_obj.address_get(cr, uid, [partner.id],
['contact', 'invoice'])
res.update(data)
return res
def get_currency_id(self, cursor, user, picking):
if picking.purchase_id:
return picking.purchase_id.pricelist_id.currency_id.id

View File

@ -22,7 +22,7 @@
<field name="inherit_id" ref="purchase.view_purchase_order_filter"/>
<field name="arch" type="xml">
<xpath expr="/search/group/filter[@string='Not Invoiced']" position="after">
<filter icon="terp-gtk-jump-to-rtl" string="Requisition" domain="[('requisition_id','!=',False)]" separator="1"/>
<filter icon="terp-gtk-jump-to-rtl" string="Requisition" domain="[('requisition_id','!=',False)]" separator="1" help="Purchase Orders with requisition"/>
</xpath>
</field>
</record>

View File

@ -1,7 +1,7 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_purchase_requisition","purchase.requisition","model_purchase_requisition","purchase.group_purchase_user",1,1,1,1
"access_purchase_requisition_line","purchase.requisition.line","model_purchase_requisition_line","purchase.group_purchase_user",1,1,1,1
"access_purchase_requisition_line_purchase_user","purchase.requisition.line","model_purchase_requisition_line","purchase.group_purchase_user",1,1,1,1
"access_purchase_requisition_manager","purchase.requisition manager","model_purchase_requisition","purchase.group_purchase_manager",1,0,0,0
"access_purchase_requisition_line_manager","purchase.requisition.line manager","model_purchase_requisition_line","purchase.group_purchase_manager",1,0,0,0
"access_purchase_requisition","purchase.requisition","model_purchase_requisition","stock.group_stock_manager",1,0,1,0
"access_purchase_requisition_line","purchase.requisition.line","model_purchase_requisition_line","stock.group_stock_manager",1,0,1,0
"access_purchase_requisition_stock_manager","purchase.requisition","model_purchase_requisition","stock.group_stock_manager",1,0,1,0
"access_purchase_requisition_line_stock_manager","purchase.requisition.line","model_purchase_requisition_line","stock.group_stock_manager",1,0,1,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_purchase_requisition purchase.requisition model_purchase_requisition purchase.group_purchase_user 1 1 1 1
3 access_purchase_requisition_line access_purchase_requisition_line_purchase_user purchase.requisition.line model_purchase_requisition_line purchase.group_purchase_user 1 1 1 1
4 access_purchase_requisition_manager purchase.requisition manager model_purchase_requisition purchase.group_purchase_manager 1 0 0 0
5 access_purchase_requisition_line_manager purchase.requisition.line manager model_purchase_requisition_line purchase.group_purchase_manager 1 0 0 0
6 access_purchase_requisition access_purchase_requisition_stock_manager purchase.requisition model_purchase_requisition stock.group_stock_manager 1 0 1 0
7 access_purchase_requisition_line access_purchase_requisition_line_stock_manager purchase.requisition.line model_purchase_requisition_line stock.group_stock_manager 1 0 1 0

View File

@ -4,6 +4,9 @@
<record id="base.de" model="res.country">
<field eval="True" name="intrastat"/>
</record>
<record id="base.be" model="res.country">
<field eval="True" name="intrastat"/>
</record>
<record id="base.at" model="res.country">
<field eval="True" name="intrastat"/>
</record>

View File

@ -705,7 +705,6 @@ class sale_order(osv.osv):
#'state': 'waiting',
'note': line.notes,
'company_id': order.company_id.id,
'returned_price': line.price_unit,
})
if line.product_id:
@ -739,12 +738,13 @@ class sale_order(osv.osv):
proc_obj.write(cr, uid, [proc_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
val = {}
for proc_id in proc_ids:
wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
if picking_id:
wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
for proc_id in proc_ids:
wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
if order.state == 'shipping_except':
val['state'] = 'progress'
val['shipped'] = False

View File

@ -172,6 +172,7 @@
<page groups="base.group_extended" string="Extra Info">
<field name="th_weight"/>
<field name="address_allotment_id"/>
<field name="property_ids" colspan="4"/>
</page>
<page string="Notes">
<field colspan="4" name="notes" nolabel="1"/>

View File

@ -106,7 +106,7 @@
<separator string="Stocks" colspan="4"/>
<field name="qty_available"/>
<button name="%(action_view_change_product_quantity)d" string="Update" attrs="{'invisible': [('type', '=', 'service')]}"
type="action" icon="gtk-execute" groups = "stock.group_stock_manager,base.group_sale_manager,purchase.group_purchase_manager,stock.group_stock_manager,mrp.group_mrp_manager"/>
type="action" icon="gtk-execute" groups = "stock.group_stock_manager,stock.group_stock_user"/>
<newline/>
<field name="virtual_available"/>
</group>

View File

@ -864,8 +864,7 @@ class stock_picking(osv.osv):
@return {'contact': address, 'invoice': address} for invoice
"""
partner_obj = self.pool.get('res.partner')
partner = (picking.purchase_id and picking.purchase_id.partner_id) or (picking.sale_id and picking.sale_id.partner_id) or picking.address_id.partner_id
partner = picking.address_id.partner_id
return partner_obj.address_get(cr, uid, [partner.id],
['contact', 'invoice'])
@ -960,6 +959,7 @@ class stock_picking(osv.osv):
invoice_obj = self.pool.get('account.invoice')
invoice_line_obj = self.pool.get('account.invoice.line')
address_obj = self.pool.get('res.partner.address')
invoices_group = {}
res = {}
inv_type = type
@ -983,6 +983,7 @@ class stock_picking(osv.osv):
address_contact_id, address_invoice_id = \
self._get_address_invoice(cr, uid, picking).values()
address = address_obj.browse(cr, uid, address_contact_id, context=context)
comment = self._get_comment_invoice(cr, uid, picking)
if group and partner.id in invoices_group:
@ -1002,7 +1003,7 @@ class stock_picking(osv.osv):
'origin': (picking.name or '') + (picking.origin and (':' + picking.origin) or ''),
'type': inv_type,
'account_id': account_id,
'partner_id': partner.id,
'partner_id': address.partner_id.id,
'address_invoice_id': address_invoice_id,
'address_contact_id': address_contact_id,
'comment': comment,
@ -1159,6 +1160,7 @@ class stock_picking(osv.osv):
complete, too_many, too_few = [], [], []
move_product_qty = {}
prodlot_ids = {}
product_avail = {}
for move in pick.move_lines:
if move.state in ('done', 'cancel'):
continue
@ -1184,6 +1186,12 @@ class stock_picking(osv.osv):
move_currency_id = move.company_id.currency_id.id
context['currency_id'] = move_currency_id
qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
if product.id in product_avail:
product_avail[product.id] += qty
else:
product_avail[product.id] = product.qty_available
if qty > 0:
new_price = currency_obj.compute(cr, uid, product_currency,
move_currency_id, product_price)
@ -1194,9 +1202,8 @@ class stock_picking(osv.osv):
else:
# Get the standard price
amount_unit = product.price_get('standard_price', context)[product.id]
new_std_price = ((amount_unit * product.qty_available)\
+ (new_price * qty))/(product.qty_available + qty)
new_std_price = ((amount_unit * product_avail[product.id])\
+ (new_price * qty))/(product_avail[product.id] + qty)
# Write the field according to price type field
product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price})
@ -1206,8 +1213,6 @@ class stock_picking(osv.osv):
{'price_unit': product_price,
'price_currency_id': product_currency})
if not move.returned_price:
move_obj.write(cr, uid, [move.id], {'returned_price': move.price_unit})
for move in too_few:
product_qty = move_product_qty[move.id]
@ -1547,7 +1552,6 @@ class stock_move(osv.osv):
# used for colors in tree views:
'scrapped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scrapped', readonly=True),
'returned_price': fields.float('Returned product price', digits_compute= dp.get_precision('Sale Price')),
}
_constraints = [
(_check_tracking,
@ -1784,7 +1788,7 @@ class stock_move(osv.osv):
picking_obj = self.pool.get('stock.picking')
pick_id= picking_obj.create(cr, uid, {
'name': pick_name,
'origin': str(picking.origin or ''),
'origin': tools.ustr(picking.origin or ''),
'type': ptype,
'note': picking.note,
'move_type': picking.move_type,
@ -1796,6 +1800,51 @@ class stock_move(osv.osv):
'date': picking.date,
})
return pick_id
def create_chained_picking(self, cr, uid, moves, context=None):
res_obj = self.pool.get('res.company')
location_obj = self.pool.get('stock.location')
move_obj = self.pool.get('stock.move')
wf_service = netsvc.LocalService("workflow")
new_moves = []
if context is None:
context = {}
seq_obj = self.pool.get('ir.sequence')
for picking, todo in self._chain_compute(cr, uid, moves, context=context).items():
ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
if picking:
# name of new picking according to its type
new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
# Need to check name of old picking because it always considers picking as "OUT" when created from Sale Order
old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
if old_ptype != picking.type:
old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
self.pool.get('stock.picking').write(cr, uid, picking.id, {'name': old_pick_name}, context=context)
else:
pickid = False
for move, (loc, dummy, delay, dummy, company_id, ptype) in todo:
new_id = move_obj.copy(cr, uid, move.id, {
'location_id': move.location_dest_id.id,
'location_dest_id': loc.id,
'date_moved': time.strftime('%Y-%m-%d'),
'picking_id': pickid,
'state': 'waiting',
'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
'move_history_ids': [],
'date': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
'move_history_ids2': []}
)
move_obj.write(cr, uid, [move.id], {
'move_dest_id': new_id,
'move_history_ids': [(4, new_id)]
})
new_moves.append(self.browse(cr, uid, [new_id])[0])
if pickid:
wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
if new_moves:
new_moves += self.create_chained_picking(cr, uid, new_moves, context)
return new_moves
def action_confirm(self, cr, uid, ids, context=None):
""" Confirms stock move.
@return: List of ids.
@ -1807,46 +1856,7 @@ class stock_move(osv.osv):
move_obj = self.pool.get('stock.move')
wf_service = netsvc.LocalService("workflow")
def create_chained_picking(self, cr, uid, moves, context=None):
new_moves = []
if context is None:
context = {}
seq_obj = self.pool.get('ir.sequence')
for picking, todo in self._chain_compute(cr, uid, moves, context=context).items():
ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
if picking:
# name of new picking according to its type
new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
# Need to check name of old picking because it always considers picking as "OUT" when created from Sale Order
old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
if old_ptype != picking.type:
old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
self.pool.get('stock.picking').write(cr, uid, picking.id, {'name': old_pick_name}, context=context)
else:
pickid = False
for move, (loc, dummy, delay, dummy, company_id, ptype) in todo:
new_id = move_obj.copy(cr, uid, move.id, {
'location_id': move.location_dest_id.id,
'location_dest_id': loc.id,
'date_moved': time.strftime('%Y-%m-%d'),
'picking_id': pickid,
'state': 'waiting',
'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
'move_history_ids': [],
'date': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
'move_history_ids2': []}
)
move_obj.write(cr, uid, [move.id], {
'move_dest_id': new_id,
'move_history_ids': [(4, new_id)]
})
new_moves.append(self.browse(cr, uid, [new_id])[0])
if pickid:
wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
if new_moves:
create_chained_picking(self, cr, uid, new_moves, context)
create_chained_picking(self, cr, uid, moves, context)
self.create_chained_picking(cr, uid, moves, context)
return []
def action_assign(self, cr, uid, ids, *args):
@ -2114,6 +2124,8 @@ class stock_move(osv.osv):
prodlot_id = partial_datas and partial_datas.get('move%s_prodlot_id' % (move.id), False)
if prodlot_id:
self.write(cr, uid, [move.id], {'prodlot_id': prodlot_id}, context=context)
if move.state not in ('confirmed','done'):
self.action_confirm(cr, uid, move_ids, context=context)
self.write(cr, uid, move_ids, {'state': 'done', 'date_planned': time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
for id in move_ids:
@ -2218,6 +2230,8 @@ class stock_move(osv.osv):
'tracking_id': move.tracking_id.id,
'prodlot_id': move.prodlot_id.id,
}
if move.location_id.usage <> 'internal':
default_val.update({'location_id': move.location_dest_id.id})
new_move = self.copy(cr, uid, move.id, default_val)
res += [new_move]
@ -2568,22 +2582,33 @@ class stock_inventory(osv.osv):
self.write(cr, uid, [inv.id], {'state': 'confirm', 'move_ids': [(6, 0, move_ids)]})
return True
def action_cancel(self, cr, uid, ids, context=None):
def action_cancel_draft(self, cr, uid, ids, context=None):
""" Cancels the stock move and change inventory state to draft.
@return: True
"""
for inv in self.browse(cr, uid, ids, context=context):
self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context)
self.write(cr, uid, [inv.id], {'state': 'draft'})
self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context=context)
self.write(cr, uid, [inv.id], {'state':'draft'}, context=context)
return True
def action_cancel_inventary(self, cr, uid, ids, context=None):
""" Cancels both stock move and inventory
@return: True
"""
move_obj = self.pool.get('stock.move')
account_move_obj = self.pool.get('account.move')
for inv in self.browse(cr, uid, ids, context=context):
self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context)
self.write(cr, uid, [inv.id], {'state':'cancel'})
move_obj.action_cancel(cr, uid, [x.id for x in inv.move_ids], context=context)
for move in inv.move_ids:
account_move_ids = account_move_obj.search(cr, uid, [('name', '=', move.name)])
if account_move_ids:
account_move_data_l = account_move_obj.read(cr, uid, account_move_ids, ['state'], context=context)
for account_move in account_move_data_l:
if account_move['state'] == 'posted':
raise osv.except_osv(_('UserError'),
_('You can not cancel inventory which has any account move with posted state.'))
account_move_obj.unlink(cr, uid, [account_move['id']], context=context)
self.write(cr, uid, [inv.id], {'state': 'cancel'}, context=context)
return True
stock_inventory()

View File

@ -170,11 +170,11 @@
<group col="2" colspan="2">
<field name="state"/>
</group>
<group col="2" colspan="2">
<button name="action_cancel_inventary" states="draft" string="Cancel Inventory" type="object" icon="gtk-cancel"/>
<group col="3" colspan="2">
<button name="action_cancel_inventary" states="draft,confirm,done" string="Cancel Inventory" type="object" icon="gtk-cancel"/>
<button name="action_confirm" states="draft" string="Confirm Inventory" type="object" icon="gtk-apply"/>
<button name="action_done" states="confirm" string="Validate Inventory" type="object" icon="gtk-jump-to"/>
<button name="action_cancel" states="cancel" string="Set to Draft" type="object" icon="gtk-convert"/>
<button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" icon="gtk-convert"/>
</group>
</form>
</field>
@ -773,7 +773,7 @@
<button name="action_assign" states="confirmed" string="Check Availability" type="object" icon="gtk-find"/>
<button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/>
<button name="action_process" states="assigned" string="Process" groups="stock.group_stock_user" type="object" icon="gtk-go-forward"/>
<button states="done" name="%(action_stock_invoice_onshipping)d" string="Create Invoice" type="action" icon="terp-gtk-go-back-rtl" />
<button states="done" name="%(action_stock_invoice_onshipping)d" string="Create Invoice" attrs="{'invisible': ['|',('invoice_state','=','invoiced'),('invoice_state','=','none')]}" type="action" icon="terp-gtk-go-back-rtl" />
</group>
</page>
<page string="Additional info" groups="base.group_extended,base.group_multi_company">
@ -967,7 +967,7 @@
<button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/>
<button name="action_process" states="assigned" string="Process" type="object" icon="gtk-go-forward"/>
<button name="%(act_stock_return_picking)d" string="Return Products" states="done" type="action" icon="gtk-execute"/>
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" states="done" type="action" icon="terp-gtk-go-back-rtl"/>
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" states="done" attrs="{'invisible': ['|',('invoice_state','=','invoiced'),('invoice_state','=','none')]}" type="action" icon="terp-gtk-go-back-rtl"/>
</group>
</page>
<page string="Additional info" groups="base.group_extended,base.group_multi_company">
@ -1189,7 +1189,7 @@
<group colspan="1" states="done">
<button name="%(act_stock_return_picking)d" string="Return Products" states="done" type="action" icon="gtk-execute"/>
</group>
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" type="action" icon="terp-gtk-go-back-rtl"/>
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" attrs="{'invisible': ['|',('invoice_state','=','invoiced'),('invoice_state','=','none')]}" type="action" icon="terp-gtk-go-back-rtl" />
</group>
</page>
<page string="Additional Info" groups="base.group_extended,base.group_multi_company">

View File

@ -32,6 +32,19 @@ class stock_change_product_qty(osv.osv_memory):
'location_id': fields.many2one('stock.location', 'Location', required=True, domain="[('usage', '=', 'internal')]"),
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
result = super(stock_change_product_qty, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
product_id = context and context.get('active_id', False) or False
if (context.get('active_model') == 'product.product') and product_id:
prod_obj = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
fields = result.get('fields', {})
if fields and (prod_obj.track_production == True) and (fields.get('prodlot_id')):
result['fields']['prodlot_id']['required'] = True
else:
result['fields']['prodlot_id']['required'] = False
return result
def default_get(self, cr, uid, fields, context):
""" To get default values for the object.
@param self: The object pointer.

View File

@ -85,34 +85,18 @@ class stock_invoice_onshipping(osv.osv_memory):
raise osv.except_osv(_('Warning !'), _('None of these picking lists require invoicing.'))
return res
def create_invoice(self, cr, uid, ids, context=None):
def open_invoice(self, cr, uid, ids, context=None):
if context is None:
context = {}
picking_pool = self.pool.get('stock.picking')
data_pool = self.pool.get('ir.model.data')
onshipdata_obj = self.read(cr, uid, ids[0], ['journal_id', 'group', 'invoice_date'])
if context.get('new_picking', False):
onshipdata_obj['id'] = onshipdata_obj.new_picking
onshipdata_obj[ids] = onshipdata_obj.new_picking
context['date_inv'] = onshipdata_obj['invoice_date']
invoice_ids = []
active_ids = context.get('active_ids', [])
active_picking = picking_pool.browse(cr, uid, context.get('active_id',False), context=context)
inv_type = picking_pool._get_invoice_type(active_picking)
res = picking_pool.action_invoice_create(cr, uid, active_ids,
journal_id = onshipdata_obj['journal_id'],
group = onshipdata_obj['group'],
type = None,
context=context)
data_pool = self.pool.get('ir.model.data')
res = self.create_invoice(cr, uid, ids, context=context)
invoice_ids += res.values()
if not invoice_ids:
raise osv.except_osv(_('Error'), _('No Invoices were created'))
inv_type = context.get('inv_type', False)
action_model = False
action = {}
if not invoice_ids:
raise osv.except_osv(_('Error'), _('No Invoices were created'))
if inv_type == "out_invoice":
action_model,action_id = data_pool.get_object_reference(cr, uid, 'account', "action_invoice_tree1")
elif inv_type == "in_invoice":
@ -127,6 +111,26 @@ class stock_invoice_onshipping(osv.osv_memory):
action['domain'] = "[('id','in', ["+','.join(map(str,invoice_ids))+"])]"
return action
def create_invoice(self, cr, uid, ids, context=None):
if context is None:
context = {}
picking_pool = self.pool.get('stock.picking')
onshipdata_obj = self.read(cr, uid, ids, ['journal_id', 'group', 'invoice_date'])
if context.get('new_picking', False):
onshipdata_obj['id'] = onshipdata_obj.new_picking
onshipdata_obj[ids] = onshipdata_obj.new_picking
context['date_inv'] = onshipdata_obj[0]['invoice_date']
active_ids = context.get('active_ids', [])
active_picking = picking_pool.browse(cr, uid, context.get('active_id',False), context=context)
inv_type = picking_pool._get_invoice_type(active_picking)
context['inv_type'] = inv_type
res = picking_pool.action_invoice_create(cr, uid, active_ids,
journal_id = onshipdata_obj[0]['journal_id'],
group = onshipdata_obj[0]['group'],
type = None,
context=context)
return res
stock_invoice_onshipping()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -15,7 +15,7 @@
<field name="invoice_date" />
<separator string="" colspan="4" />
<button special="cancel" string="_Cancel" icon='gtk-cancel'/>
<button name="create_invoice" string="Create" type="object" icon="terp-gtk-go-back-rtl"/>
<button name="open_invoice" string="Create" type="object" icon="terp-gtk-go-back-rtl"/>
</form>
</field>
</record>

View File

@ -33,51 +33,71 @@ class stock_partial_picking(osv.osv_memory):
'product_moves_in' : fields.one2many('stock.move.memory.in', 'wizard_id', 'Moves'),
}
def __is_in(self,cr, uid, pick_ids):
def get_picking_type(self, cr, uid, picking, context=None):
picking_type = picking.type
for move in picking.move_lines:
if picking.type == 'in' and move.product_id.cost_method == 'average':
picking_type = 'in'
break
else:
picking_type = 'out'
return picking_type
def default_get(self, cr, uid, fields, context=None):
""" To get default values for the object.
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param fields: List of fields for which we want default values
@param context: A standard dictionary
@return: A dictionary which of fields with values.
"""
@return: True if one of the moves has as picking type 'in'
"""
if not pick_ids:
return False
if context is None:
context = {}
pick_obj = self.pool.get('stock.picking')
res = super(stock_partial_picking, self).default_get(cr, uid, fields, context=context)
picking_ids = context.get('active_ids', [])
if not picking_ids:
return res
result = []
for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
pick_type = self.get_picking_type(cr, uid, pick, context=context)
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
result.append(self.__create_partial_picking_memory(m, pick_type))
if 'product_moves_in' in fields:
res.update({'product_moves_in': result})
if 'product_moves_out' in fields:
res.update({'product_moves_out': result})
if 'date' in fields:
res.update({'date': time.strftime('%Y-%m-%d %H:%M:%S')})
return res
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
result = super(stock_partial_picking, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
pick_obj = self.pool.get('stock.picking')
pick_ids = pick_obj.search(cr, uid, [('id','in',pick_ids)])
for pick in pick_obj.browse(cr, uid, pick_ids):
for move in pick.move_lines:
if pick.type == 'in' and move.product_id.cost_method == 'average':
return True
return False
def __get_picking_type(self, cr, uid, pick_ids):
if self.__is_in(cr, uid, pick_ids):
return "product_moves_in"
else:
return "product_moves_out"
def view_init(self, cr, uid, fields_list, context=None):
res = super(stock_partial_picking, self).view_init(cr, uid, fields_list, context=context)
return res
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False,submenu=False):
result = super(stock_partial_picking, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu)
picking_ids = context.get('active_ids', False)
picking_type = self.__get_picking_type(cr, uid, picking_ids)
for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
picking_type = self.get_picking_type(cr, uid, pick, context=context)
_moves_arch_lst = """<form string="%s">
<field name="date" invisible="1"/>
<separator colspan="4" string="%s"/>
<field name="%s" colspan="4" nolabel="1" mode="tree,form" width="550" height="200" ></field>
""" % (_('Process Document'), _('Products'), picking_type)
""" % (_('Process Document'), _('Products'), "product_moves_" + picking_type)
_moves_fields = result['fields']
# add field related to picking type only
_moves_fields.update({
'product_moves_in' : {'relation': 'stock.move.memory.in', 'type' : 'one2many', 'string' : 'Product Moves'},
'product_moves_out' : {'relation': 'stock.move.memory.out', 'type' : 'one2many', 'string' : 'Product Moves'}
'product_moves_' + picking_type: {'relation': 'stock.move.memory.'+picking_type, 'type' : 'one2many', 'string' : 'Product Moves'},
})
_moves_arch_lst += """
<separator string="" colspan="4" />
<label string="" colspan="2"/>
@ -92,44 +112,22 @@ class stock_partial_picking(osv.osv_memory):
result['fields'] = _moves_fields
return result
def __create_partial_picking_memory(self, picking, is_in):
def __create_partial_picking_memory(self, picking, pick_type):
move_memory = {
'product_id' : picking.product_id.id,
'quantity' : picking.product_qty,
'product_uom' : picking.product_uom.id,
'prodlot_id' : picking.prodlot_id.id,
'move_id' : picking.id,
'product_id' : picking.product_id.id,
'quantity' : picking.product_qty,
'product_uom' : picking.product_uom.id,
'prodlot_id' : picking.prodlot_id.id,
'move_id' : picking.id,
}
if is_in:
if pick_type == 'in':
move_memory.update({
'cost' : picking.product_id.standard_price,
'currency' : picking.product_id.company_id and picking.product_id.company_id.currency_id and picking.product_id.company_id.currency_id.id or False,
'cost' : picking.product_id.standard_price,
'currency' : picking.product_id.company_id.currency_id.id,
})
return move_memory
def __get_active_stock_pickings(self, cr, uid, context=None):
pick_obj = self.pool.get('stock.picking')
if not context:
context = {}
res = []
for pick in pick_obj.browse(cr, uid, context.get('active_ids', []), context):
need_product_cost = (pick.type == 'in')
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
res.append(self.__create_partial_picking_memory(m, need_product_cost))
return res
_defaults = {
'product_moves_in' : __get_active_stock_pickings,
'product_moves_out' : __get_active_stock_pickings,
'date' : lambda *a : time.strftime('%Y-%m-%d %H:%M:%S'),
}
def do_partial(self, cr, uid, ids, context=None):
""" Makes partial moves and pickings done.
@param self: The object pointer.
@ -140,6 +138,9 @@ class stock_partial_picking(osv.osv_memory):
@return: A dictionary which of fields with values.
"""
pick_obj = self.pool.get('stock.picking')
move_obj = self.pool.get('stock.move')
location_obj = self.pool.get('stock.location')
picking_ids = context.get('active_ids', False)
partial = self.browse(cr, uid, ids[0], context=context)
partial_datas = {
@ -147,40 +148,24 @@ class stock_partial_picking(osv.osv_memory):
}
for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
need_product_cost = (pick.type == 'in')
moves_list = need_product_cost and partial.product_moves_in or partial.product_moves_out
p_moves = {}
for product_move in moves_list:
p_moves[product_move.move_id.id] = product_move
for move in pick.move_lines:
if move.state in ('done', 'cancel'):
continue
if not p_moves.get(move.id):
continue
partial_datas['move%s' % (move.id)] = {
'product_id' : p_moves[move.id].id,
'product_qty' : p_moves[move.id].quantity,
'product_uom' :p_moves[move.id].product_uom.id,
'prodlot_id' : p_moves[move.id].prodlot_id.id,
picking_type = self.get_picking_type(cr, uid, pick, context=context)
moves_list = picking_type == 'in' and partial.product_moves_in or partial.product_moves_out
for move in moves_list:
partial_datas['move%s' % (move.move_id.id)] = {
'product_id': move.id,
'product_qty': move.quantity,
'product_uom': move.product_uom.id,
'prodlot_id': move.prodlot_id.id,
}
if (move.picking_id.type == 'in') and (move.product_id.cost_method == 'average'):
partial_datas['move%s' % (move.id)].update({
'product_price' : p_moves[move.id].cost,
'product_currency': p_moves[move.id].currency.id,
if (picking_type == 'in') and (move.product_id.cost_method == 'average'):
partial_datas['move%s' % (move.move_id.id)].update({
'product_price' : move.cost,
'product_currency': move.currency.id,
})
pick_obj.do_partial(cr, uid, picking_ids, partial_datas, context=context)
return {'type': 'ir.actions.act_window_close'}
return {}
stock_partial_picking()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -53,10 +53,8 @@ class stock_return_picking(osv.osv_memory):
res['invoice_state'] = 'none'
for line in pick.move_lines:
return_id = 'return%s'%(line.id)
return_price = 'return_price%s'%(line.id)
if return_id in fields:
res[return_id] = line.product_qty
res[return_price]=line.price_unit
return res
def view_init(self, cr, uid, fields_list, context=None):
@ -88,11 +86,8 @@ class stock_return_picking(osv.osv_memory):
valid_lines += 1
if 'return%s'%(m.id) not in self._columns:
self._columns['return%s'%(m.id)] = fields.float(string=m.name, required=True)
if 'return_price%s'%(m.id) not in self._columns:
self._columns['return_price%s'%(m.id)] = fields.float(string=m.name, required=True)
if 'invoice_state' not in self._columns:
self._columns['invoice_state'] = fields.selection([('2binvoiced', 'To be refunded/invoiced'), ('none', 'No invoicing')], string='Invoicing', required=True)
if not valid_lines:
raise osv.except_osv(_('Warning !'), _("There are no products to return (only lines in Done state and not fully returned yet can be returned)!"))
return res
@ -126,10 +121,6 @@ class stock_return_picking(osv.osv_memory):
if m.state=='done' and quantity > return_history[m.id]:
arch_lst.append('<field name="return%s"/>\n<newline/>' % (m.id,))
res['fields']['return%s' % m.id]={'string':m.name, 'type':'float', 'required':True}
if m.product_id.cost_method == 'average' and pick.type == 'in':
arch_lst.append('<field name="return_price%s"/>\n<newline/>' % (m.id,))
res['fields']['return_price%s' % m.id]={'string':'Price', 'type':'float', 'required':True}
res.setdefault('returns', []).append(m.id)
arch_lst.append('<field name="invoice_state"/>\n<newline/>')
res['fields']['invoice_state']={'string':_('Invoicing'), 'type':'selection','required':True, 'selection':[('2binvoiced', _('To be refunded/invoiced')), ('none', _('No invoicing'))]}
@ -142,7 +133,7 @@ class stock_return_picking(osv.osv_memory):
return res
def create_returns(self, cr, uid, ids, context=None):
"""
"""
Creates return picking.
@param self: The object pointer.
@param cr: A database cursor
@ -152,13 +143,13 @@ class stock_return_picking(osv.osv_memory):
@return: A dictionary which of fields with values.
"""
if context is None:
context = {}
context = {}
record_id = context and context.get('active_id', False) or False
move_obj = self.pool.get('stock.move')
pick_obj = self.pool.get('stock.picking')
uom_obj = self.pool.get('product.uom')
wf_service = netsvc.LocalService("workflow")
pick = pick_obj.browse(cr, uid, record_id, context=context)
data = self.read(cr, uid, ids[0])
new_picking = None
@ -180,7 +171,6 @@ class stock_return_picking(osv.osv_memory):
new_location=move.location_dest_id.id
if move.state=='done':
new_qty = data['return%s' % move.id]
price_unit = data['return_price%s' % move.id]
returned_qty = move.product_qty
for rec in move.move_history_ids2:
@ -188,6 +178,7 @@ class stock_return_picking(osv.osv_memory):
if returned_qty != new_qty:
set_invoice_state_to_none = False
if new_qty:
returned_lines += 1
new_move=move_obj.copy(cr, uid, move.id, {
@ -196,8 +187,7 @@ class stock_return_picking(osv.osv_memory):
new_qty, move.product_uos.id),
'picking_id':new_picking, 'state':'draft',
'location_id':new_location, 'location_dest_id':move.location_id.id,
'date':date_cur,
'price_unit':price_unit})
'date':date_cur,})
move_obj.write(cr, uid, [move.id], {'move_history_ids2':[(4,new_move)]})
if not returned_lines: