[MERGE] merged the dev2 branch
bzr revid: qdp-launchpad@tinyerp.com-20110117101958-mb28vtb0qckoayn3
This commit is contained in:
commit
23606385d4
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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:
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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"/>
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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),
|
||||
'|',
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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','<>','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"/>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue