[FIX] Refund creation

[IMP] on change from invoice selection create line with destination
[IMP] Add return location on claim lines
This commit is contained in:
Joel Grand-Guillaume
2013-11-15 12:00:25 +01:00
parent 086b8203c0
commit d9268062d3
8 changed files with 67 additions and 202 deletions

View File

@@ -59,7 +59,6 @@ Using this module make the logistic flow of return this way:
'stock_view.xml',
'res_company_view.xml',
'crm_claim_rma_data.xml',
'stock_data.xml',
],
'images': ['images/product_return.png', 'images/claim.png','images/return_line.png','images/exchange.png'],
'installable': True,

View File

@@ -19,7 +19,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import fields, orm
from openerp.osv import fields, orm, osv
from tools.translate import _
@@ -31,17 +31,13 @@ class account_invoice(orm.Model):
'claim_id': fields.many2one('crm.claim', 'Claim'),
}
def _get_cleanup_fields(self, cr, uid, context=None):
fields = super(account_invoice, self)._get_cleanup_fields(cr, uid,
context=context)
fields = fields + ('claim_line_id',)
return fields
def _refund_cleanup_lines(self, cr, uid, lines, context=None):
"""Override when from claim to update the quantity and link
to the claim line."""
if context is None: context = {}
new_lines = []
# check if is an invoice_line
if context.get('claim_line_ids') and lines and 'product_id' in lines[0]:
# check if is an invoice_line and we are from a claim
if context.get('claim_line_ids') and lines and lines[0]._name =='account.invoice.line' :
for claim_line_id in context.get('claim_line_ids'):
claim_info = self.pool.get('claim.line').read(cr, uid,
claim_line_id[1],
@@ -51,12 +47,13 @@ class account_invoice(orm.Model):
'refund_line_id'],
context=context)
if not claim_info['refund_line_id']:
#For each lines replace quantity and add clain_line_id
inv_line_obj = self.pool.get('account.invoice.line')
inv_line = inv_line_obj.browse(cr, uid,
[claim_info['invoice_line_id'][0]],
context=context)[0]
clean_line = {}
for field in invoice_line_info._all_columns.keys():
for field in inv_line._all_columns.keys():
column_type = inv_line._all_columns[field].column._type
if column_type == 'many2one':
clean_line[field] = inv_line[field].id
@@ -75,15 +72,22 @@ class account_invoice(orm.Model):
# not instead of raise an error
raise osv.except_osv(_('Error !'),
_('A refund has already been created for this claim !'))
else:
return super(account_invoice, self)._refund_cleanup_lines(cr, uid, lines, context=None)
return map(lambda x: (0,0,x), new_lines)
def _prepare_refund(self, cr, uid, *args, **kwargs):
result = super(account_invoice, self)._prepare_refund(cr, uid,
*args, **kwargs)
if kwargs.get('context') and kwargs['context'].get('claim_id'):
result['claim_id'] = kwargs['context']['claim_id']
def _prepare_refund(self, cr, uid, invoice, date=None, period_id=None,
description=None, journal_id=None, context=None):
if context is None:
context={}
result = super(account_invoice, self)._prepare_refund(cr, uid, invoice,
date=date, period_id=period_id, description=description,
journal_id=journal_id, context=context)
if context.get('claim_id'):
result['claim_id'] = context.get('claim_id')
return result
class account_invoice_line(orm.Model):
_inherit = "account.invoice.line"

View File

@@ -54,7 +54,7 @@ class claim_line(orm.Model):
# Comment written in a claim.line to know about the warranty status
WARRANT_COMMENT = {
'valid': "Valid",
'expired': "Expired"
'expired': "Expired",
'not_define': "Not Defined"}
# Method to calculate total amount of the line : qty*UP
@@ -163,11 +163,6 @@ class claim_line(orm.Model):
'name': lambda *a: 'none',
}
def write(self, cr, uid, ids, vals, context=None):
res = super(claim_line, self).write(cr, uid, ids, vals, context=context)
self.set_warranty(cr, uid, ids, context=context)
return res
# Method to calculate warranty limit
def set_warranty_limit(self, cr, uid, ids, claim_line, context=None):
date_invoice = claim_line.invoice_line_id.invoice_id.date_invoice
@@ -181,7 +176,7 @@ class claim_line(orm.Model):
else:
waranty_duration = int(claim_line.product_id.warranty)
limit = (date_inv_at_server +
relativedelta(month=waranty_duration).strftime(DEFAULT_SERVER_DATE_FORMAT)
relativedelta(month=waranty_duration)).strftime(DEFAULT_SERVER_DATE_FORMAT)
# If waranty period was defined
if waranty_duration > 0:
if limit < claim_line.claim_id.date:
@@ -197,6 +192,24 @@ class claim_line(orm.Model):
_('Cannot find any date for invoice ! Must be a validated invoice !'))
return True
def get_destination_location(self, cr, uid, product_id,
warehouse_id, context=None):
"""Compute and return the destination location ID to take
for a return."""
prod_obj = self.pool.get('product.product')
prod = prod_obj.browse(cr, uid, product_id, context=context)
wh_obj = self.pool.get('stock.warehouse')
wh = wh_obj.browse(cr, uid, warehouse_id, context=context)
location_dest_id = wh.lot_stock_id.id
return_type = 'company'
if prod:
seller = prod.seller_info_id
if seller:
return_type = seller.warranty_return_partner
if return_type == 'supplier':
location_dest_id = seller.name.property_stock_supplier.id
return location_dest_id
# Method to calculate warranty return address
def set_warranty_return_address(self, cr, uid, ids,
claim_line, context=None):
@@ -207,7 +220,6 @@ class claim_line(orm.Model):
if specified
- supplier: return to the supplier address"""
return_address = None
location_dest_id = claim_line.warehouse_id.lot_stock_id.id
return_type = 'company'
seller = claim_line.product_id.seller_info_id
claim_company = claim_line.claim_id.company_id
@@ -219,7 +231,10 @@ class claim_line(orm.Model):
return_type = seller.warranty_return_partner
if return_type == 'supplier':
return_address = seller.warranty_return_address.id
location_dest_id = seller.property_stock_supplier.id
location_dest_id = self.get_destination_location(cr, uid,
claim_line.product_id.id,
claim_line.claim_id.warehouse_id.id,
context=context)
self.write(cr, uid, ids,
{'warranty_return_partner': return_address,
'warranty_type': return_type,
@@ -334,12 +349,20 @@ class crm_claim(orm.Model):
res['value']['partner_phone'] = other_add.phone
return res
def onchange_invoice_id(self, cr, uid, ids, invoice_id, context=None):
def onchange_invoice_id(self, cr, uid, ids, invoice_id,
warehouse_id, context=None):
invoice_line_obj = self.pool.get('account.invoice.line')
claim_line_obj = self.pool.get('claim.line')
invoice_line_ids = invoice_line_obj.search(cr, uid,
[('invoice_id','=',invoice_id)])
claim_lines = []
if not warehouse_id:
warehouse_id = self._get_default_warehouse(cr, uid, context=context)
for invoice_line in invoice_line_obj.browse(cr,uid,invoice_line_ids):
location_dest_id = claim_line_obj.get_destination_location(cr, uid,
invoice_line.product_id.id,
warehouse_id,
context=context)
claim_lines.append({
'name': invoice_line.name,
'claim_origine' : "none",
@@ -347,6 +370,7 @@ class crm_claim(orm.Model):
'product_id' : invoice_line.product_id.id,
'product_returned_quantity' : invoice_line.quantity,
'unit_sale_price' : invoice_line.price_unit,
'location_dest_id': location_dest_id,
'state' : 'draft',
})
return {'value' : {'claim_line_ids' : claim_lines}}

View File

@@ -58,7 +58,6 @@
<field name="substate_id"/>
<field name="product_id"/>
<field name="name"/>
<field name="product_id"/>
<field name="prodlot_id"/>
<field name="warning"/>
<field name="location_dest_id"/>
@@ -147,7 +146,7 @@
<group name="Product Return">
<separator string="Product Return" colspan="4"/>
<group>
<field name="invoice_id" on_change="onchange_invoice_id(invoice_id, context)" domain="[('partner_id','=',partner_id)]" />
<field name="invoice_id" on_change="onchange_invoice_id(invoice_id,warehouse_id,context)" domain="[('partner_id','=',partner_id)]" />
</group>
<group>
<!-- Place for mass return button from crm_rma_lot_mass_return -->

View File

@@ -21,4 +21,3 @@
##############################################################################
from . import claim_make_picking
from . import account_invoice_refund
from . import claim_make_picking_from_picking

View File

@@ -133,11 +133,11 @@ class claim_make_picking(orm.TransientModel):
picking_obj = self.pool.get('stock.picking')
if context is None: context = {}
view_obj = self.pool.get('ir.ui.view')
name = 'RMA picking out'
if context.get('picking_type') == 'out':
p_type = 'out'
write_field = 'move_out_id'
note = 'RMA picking out'
name = 'Customer picking out'
view_xml_id = 'stock_picking_form'
view_name = 'stock.picking.form'
else:
@@ -147,6 +147,7 @@ class claim_make_picking(orm.TransientModel):
write_field = 'move_in_id'
if context.get('picking_type'):
note = 'RMA picking ' + str(context.get('picking_type'))
name = note
view_id = view_obj.search(cr, uid, [
('xml_id', '=', view_xml_id),
('model', '=', 'stock.picking'),
@@ -157,13 +158,16 @@ class claim_make_picking(orm.TransientModel):
claim = self.pool.get('crm.claim').browse(cr, uid,
context['active_id'], context=context)
partner_id = claim.partner_id.id
common_dest_loc_id = self._get_common_dest_location_from_line(cr, uid,
line_ids, context=context)
if not common_dest_loc_id:
raise osv.except_osv(_('Error !'),
_('A picking cannot be created for various destination location, please '
'chose line with a same destination location.'))
line_ids = [x.id for x in wizard.claim_line_ids]
# In case of product return, we don't allow one picking for various
# product if location are different
if context.get('product_return'):
common_dest_loc_id = self._get_common_dest_location_from_line(cr, uid,
line_ids, context=context)
if not common_dest_loc_id:
raise osv.except_osv(_('Error !'),
_('A product return cannot be created for various destination location, please '
'chose line with a same destination location.'))
# create picking
picking_id = picking_obj.create(cr, uid, {
'origin': claim.number,

View File

@@ -1,164 +0,0 @@
# -*- coding: utf-8 -*-
#########################################################################
# #
# #
#########################################################################
# #
# crm_claim_rma for OpenERP #
# Copyright (C) 2009-2012 Akretion, Emmanuel Samyn, #
# Benoît GUILLOT <benoit.guillot@akretion.com> #
#This program is free software: you can redistribute it and/or modify #
#it under the terms of the GNU General Public License as published by #
#the Free Software Foundation, either version 3 of the License, or #
#(at your option) any later version. #
# #
#This program is distributed in the hope that it will be useful, #
#but WITHOUT ANY WARRANTY; without even the implied warranty of #
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
#GNU General Public License for more details. #
# #
#You should have received a copy of the GNU General Public License #
#along with this program. If not, see <http://www.gnu.org/licenses/>. #
#########################################################################
from openerp.osv import fields, orm
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
from openerp import netsvc
import time
class claim_make_picking_from_picking(orm.TransientModel):
_name = 'claim_make_picking_from_picking.wizard'
_description = 'Wizard to create pickings from picking lines'
_columns = {
'picking_line_source_location': fields.many2one('stock.location',
'Source Location',
help="Location where the returned products are from.",
required=True),
'picking_line_dest_location': fields.many2one('stock.location',
'Dest. Location',
help="Location where the system will stock the returned products.",
required=True),
'picking_line_ids': fields.many2many('stock.move',
'claim_picking_line_picking',
'claim_picking_id',
'picking_line_id',
'Picking lines'),
}
def _get_picking_lines(self, cr, uid, context):
return self.pool.get('stock.picking').read(cr, uid,
context['active_id'], ['move_lines'], context=context)['move_lines']
# Get default source location
def _get_source_loc(self, cr, uid, context):
if context is None: context = {}
warehouse_obj = self.pool.get('stock.warehouse')
warehouse_id = context.get('warehouse_id')
return warehouse_obj.read(cr, uid,
warehouse_id, ['lot_rma_id'], context=context)['lot_rma_id'][0]
# Get default destination location
def _get_dest_loc(self, cr, uid, context):
if context is None: context = {}
warehouse_obj = self.pool.get('stock.warehouse')
warehouse_id = context.get('warehouse_id')
print warehouse_id
if context.get('picking_type'):
context_loc = context.get('picking_type')[8:]
loc_field = 'lot_%s_id' %context.get('picking_type')[8:]
loc_id = warehouse_obj.read(cr, uid,
[warehouse_id], [loc_field], context=context)[loc_field][0]
return loc_id
_defaults = {
'picking_line_source_location': _get_source_loc,
'picking_line_dest_location': _get_dest_loc,
'picking_line_ids': _get_picking_lines,
}
def action_cancel(self,cr,uid,ids,conect=None):
return {'type': 'ir.actions.act_window_close',}
# If "Create" button pressed
def action_create_picking_from_picking(self, cr, uid, ids, context=None):
picking_obj = self.pool.get('stock.picking')
move_obj = self.pool.get('stock.move')
view_obj = self.pool.get('ir.ui.view')
if context is None: context = {}
p_type = 'internal'
if context.get('picking_type'):
context_type = context.get('picking_type')[8:]
note = 'Internal picking from RMA to %s' %context_type
name = 'Internal picking to %s' %context_type
view_id = view_obj.search(cr, uid, [
('xml_id', '=', 'view_picking_form'),
('model', '=', 'stock.picking'),
('type', '=', 'form'),
('name', '=', 'stock.picking.form')
], context=context)[0]
wizard = self.browse(cr, uid, ids[0], context=context)
prev_picking = picking_obj.browse(cr, uid,
context['active_id'], context=context)
partner_id = prev_picking.partner_id.id
# create picking
picking_id = picking_obj.create(cr, uid, {
'origin': prev_picking.origin,
'type': p_type,
'move_type': 'one', # direct
'state': 'draft',
'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'partner_id': prev_picking.partner_id.id,
'invoice_state': "none",
'company_id': prev_picking.company_id.id,
'location_id': wizard.picking_line_source_location.id,
'location_dest_id': wizard.picking_line_dest_location.id,
'note' : note,
'claim_id': prev_picking.claim_id.id,
})
# Create picking lines
for wizard_picking_line in wizard.picking_line_ids:
move_id = move_obj.create(cr, uid, {
'name' : wizard_picking_line.product_id.name_template, # Motif : crm id ? stock_picking_id ?
'priority': '0',
#'create_date':
'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'date_expected': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'product_id': wizard_picking_line.product_id.id,
'product_qty': wizard_picking_line.product_qty,
'product_uom': wizard_picking_line.product_uom.id,
'partner_id': prev_picking.partner_id.id,
'prodlot_id': wizard_picking_line.prodlot_id.id,
# 'tracking_id':
'picking_id': picking_id,
'state': 'draft',
'price_unit': wizard_picking_line.price_unit,
# 'price_currency_id': claim_id.company_id.currency_id.id, # from invoice ???
'company_id': prev_picking.company_id.id,
'location_id': wizard.picking_line_source_location.id,
'location_dest_id': wizard.picking_line_dest_location.id,
'note': note,
})
wizard_move = move_obj.write(cr, uid,
wizard_picking_line.id,
{'move_dest_id': move_id},
context=context)
wf_service = netsvc.LocalService("workflow")
if picking_id:
wf_service.trg_validate(uid,
'stock.picking', picking_id,'button_confirm', cr)
picking_obj.action_assign(cr, uid, [picking_id])
domain = "[('type','=','%s'),('partner_id','=',%s)]"%(p_type, partner_id)
return {
'name': '%s' % name,
'view_type': 'form',
'view_mode': 'form',
'view_id': view_id,
'domain' : domain,
'res_model': 'stock.picking',
'res_id': picking_id,
'type': 'ir.actions.act_window',
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -34,7 +34,7 @@
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'picking_type': 'in'}</field>
<field name="context">{'picking_type': 'in','product_return': True}</field>
</record>
<record id="action_claim_picking_out" model="ir.actions.act_window">