mirror of
https://github.com/OCA/rma.git
synced 2025-02-16 17:11:47 +02:00
[FIX] pep8, review
This commit is contained in:
@@ -27,41 +27,49 @@
|
|||||||
Management of Return Merchandise Authorization (RMA)
|
Management of Return Merchandise Authorization (RMA)
|
||||||
====================================================
|
====================================================
|
||||||
|
|
||||||
This module aim to improve the Claims by adding a way to manage the product returns. It
|
This module aims to improve the Claims by adding a way to manage the
|
||||||
allows you to create and manage picking from a claim. It also introduce a new object
|
product returns. It allows you to create and manage picking from a
|
||||||
the claim lines to better handle that problematic. One Claim can have several lines that concern
|
claim. It also introduces a new object: the claim lines to better
|
||||||
the return of differents products. It's for every of them that you'll be able to check the
|
handle that problematic. One Claim can have several lines that
|
||||||
warranty (still running or not).
|
concern the return of differents products. It's for every of them
|
||||||
|
that you'll be able to check the warranty (still running or not).
|
||||||
|
|
||||||
It mainly contain the following features:
|
It mainly contains the following features:
|
||||||
|
|
||||||
* product returns (one by one, mass return by invoice)
|
* product returns (one by one, mass return by invoice)
|
||||||
* warranty control & return address (based on invoice date and product form)
|
* warranty control & return address (based on invoice date and product form)
|
||||||
* product picking in / out
|
* product picking in / out
|
||||||
* product refund
|
* product refund
|
||||||
* access to related customer data (orders, invoices, refunds, picking in/out) from a claim
|
* access to related customer data (orders, invoices, refunds, picking
|
||||||
|
in/out) from a claim
|
||||||
|
|
||||||
Using this module make the logistic flow of return this way:
|
Using this module makes the logistic flow of return this way:
|
||||||
|
|
||||||
* Returning product goes into Stock or Supplier location with a incoming shipment (depending
|
* Returning product goes into Stock or Supplier location with a incoming
|
||||||
on the settings of the supplier info in the product form)
|
shipment (depending on the settings of the supplier info in the
|
||||||
|
product form)
|
||||||
* You can make a delivery from the RMA to send a new product to the Customer
|
* You can make a delivery from the RMA to send a new product to the Customer
|
||||||
|
|
||||||
""",
|
""",
|
||||||
'author': 'Akretion, Camptocamp',
|
'author': 'Akretion, Camptocamp',
|
||||||
'website': 'http://www.akretion.com, http://www.camptocamp.com',
|
'website': 'http://www.akretion.com, http://www.camptocamp.com',
|
||||||
'depends': ['sale','stock','crm_claim','product_warranty'],
|
'depends': ['sale',
|
||||||
'data': [
|
'stock',
|
||||||
'wizard/claim_make_picking_view.xml',
|
'crm_claim',
|
||||||
'crm_claim_rma_view.xml',
|
'product_warranty',
|
||||||
'security/ir.model.access.csv',
|
],
|
||||||
'account_invoice_view.xml',
|
'data': ['wizard/claim_make_picking_view.xml',
|
||||||
'stock_view.xml',
|
'crm_claim_rma_view.xml',
|
||||||
'crm_claim_rma_data.xml',
|
'security/ir.model.access.csv',
|
||||||
],
|
'account_invoice_view.xml',
|
||||||
'images': ['images/product_return.png', 'images/claim.png','images/return_line.png','images/exchange.png'],
|
'stock_view.xml',
|
||||||
|
'crm_claim_rma_data.xml',
|
||||||
|
],
|
||||||
|
'images': ['images/product_return.png',
|
||||||
|
'images/claim.png',
|
||||||
|
'images/return_line.png',
|
||||||
|
'images/exchange.png',
|
||||||
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
'active': False,
|
'auto_install': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
from openerp.osv import fields, orm, osv
|
from openerp.osv import fields, orm
|
||||||
from tools.translate import _
|
from tools.translate import _
|
||||||
|
|
||||||
|
|
||||||
@@ -32,59 +32,60 @@ class account_invoice(orm.Model):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _refund_cleanup_lines(self, cr, uid, lines, context=None):
|
def _refund_cleanup_lines(self, cr, uid, lines, context=None):
|
||||||
"""Override when from claim to update the quantity and link
|
""" Override when from claim to update the quantity and link to the
|
||||||
to the claim line."""
|
claim line."""
|
||||||
if context is None: context = {}
|
|
||||||
new_lines = []
|
|
||||||
# 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],
|
|
||||||
[
|
|
||||||
'invoice_line_id',
|
|
||||||
'product_returned_quantity',
|
|
||||||
'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 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
|
|
||||||
elif column_type not in ['many2many','one2many']:
|
|
||||||
clean_line[field] = inv_line[field]
|
|
||||||
elif field == 'invoice_line_tax_id':
|
|
||||||
tax_list = []
|
|
||||||
for tax in inv_line[field]:
|
|
||||||
tax_list.append(tax.id)
|
|
||||||
clean_line[field] = [(6,0, tax_list)]
|
|
||||||
clean_line['quantity'] = claim_info['product_returned_quantity']
|
|
||||||
clean_line['claim_line_id'] = [claim_line_id[1]]
|
|
||||||
new_lines.append(clean_line)
|
|
||||||
if not new_lines:
|
|
||||||
# TODO use custom states to show button of this wizard or
|
|
||||||
# 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, invoice, date=None, period_id=None,
|
|
||||||
description=None, journal_id=None, context=None):
|
|
||||||
if context is None:
|
if context is None:
|
||||||
context={}
|
context = {}
|
||||||
result = super(account_invoice, self)._prepare_refund(cr, uid, invoice,
|
new_lines = []
|
||||||
date=date, period_id=period_id, description=description,
|
inv_line_obj = self.pool.get('account.invoice.line')
|
||||||
|
claim_line_obj = self.pool.get('claim.line')
|
||||||
|
# check if is an invoice_line and we are from a claim
|
||||||
|
if not (context.get('claim_line_ids') and lines and
|
||||||
|
lines[0]._name =='account.invoice.line'):
|
||||||
|
return super(account_invoice, self)._refund_cleanup_lines(
|
||||||
|
cr, uid, lines, context=None)
|
||||||
|
|
||||||
|
for __, claim_line_id in context.get('claim_line_ids'):
|
||||||
|
line = claim_line_obj.browse(cr, uid, claim_line_id,
|
||||||
|
context=context)
|
||||||
|
if not line.refund_line_id:
|
||||||
|
# For each lines replace quantity and add claim_line_id
|
||||||
|
inv_line = inv_line_obj.browse(cr, uid,
|
||||||
|
line.invoice_line_id.id,
|
||||||
|
context=context)
|
||||||
|
clean_line = {}
|
||||||
|
for field_name, field in inv_line._all_columns.iteritems():
|
||||||
|
column_type = field.column._type
|
||||||
|
if column_type == 'many2one':
|
||||||
|
clean_line[field_name] = inv_line[field_name].id
|
||||||
|
elif column_type not in ('many2many', 'one2many'):
|
||||||
|
clean_line[field_name] = inv_line[field_name]
|
||||||
|
elif field_name == 'invoice_line_tax_id':
|
||||||
|
tax_list = []
|
||||||
|
for tax in inv_line[field_name]:
|
||||||
|
tax_list.append(tax.id)
|
||||||
|
clean_line[field_name] = [(6, 0, tax_list)]
|
||||||
|
clean_line['quantity'] = line['product_returned_quantity']
|
||||||
|
clean_line['claim_line_id'] = [claim_line_id]
|
||||||
|
new_lines.append(clean_line)
|
||||||
|
if not new_lines:
|
||||||
|
# TODO use custom states to show button of this wizard or
|
||||||
|
# not instead of raise an error
|
||||||
|
raise orm.except_orm(
|
||||||
|
_('Error !'),
|
||||||
|
_('A refund has already been created for this claim !'))
|
||||||
|
return [(0, 0, line) for line in new_lines]
|
||||||
|
|
||||||
|
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)
|
journal_id=journal_id, context=context)
|
||||||
if context.get('claim_id'):
|
if context.get('claim_id'):
|
||||||
result['claim_id'] = context.get('claim_id')
|
result['claim_id'] = context['claim_id']
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -97,10 +98,11 @@ class account_invoice_line(orm.Model):
|
|||||||
if vals.get('claim_line_id'):
|
if vals.get('claim_line_id'):
|
||||||
claim_line_id = vals['claim_line_id']
|
claim_line_id = vals['claim_line_id']
|
||||||
del vals['claim_line_id']
|
del vals['claim_line_id']
|
||||||
line_id = super(account_invoice_line, self).create(cr, uid,
|
line_id = super(account_invoice_line, self).create(
|
||||||
vals, context=context)
|
cr, uid, vals, context=context)
|
||||||
if claim_line_id:
|
if claim_line_id:
|
||||||
claim_line_obj = self.pool.get('claim.line')
|
claim_line_obj = self.pool.get('claim.line')
|
||||||
claim_line_obj.write(cr, uid, claim_line_id,
|
claim_line_obj.write(cr, uid, claim_line_id,
|
||||||
{'refund_line_id': line_id}, context=context)
|
{'refund_line_id': line_id},
|
||||||
|
context=context)
|
||||||
return line_id
|
return line_id
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# Copyright 2013 Camptocamp
|
# Copyright 2013 Camptocamp
|
||||||
# Copyright 2009-2013 Akretion,
|
# Copyright 2009-2013 Akretion,
|
||||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, Joel Grand-Guillaume
|
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, Joel Grand-Guillaume
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -20,28 +20,24 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from openerp.osv import fields, orm, osv
|
import time
|
||||||
# from crm import crm
|
from openerp.osv import fields, orm
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
import time
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||||
from tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from tools import DEFAULT_SERVER_DATE_FORMAT
|
|
||||||
from tools.translate import _
|
|
||||||
|
|
||||||
|
|
||||||
class substate_substate(orm.Model):
|
class substate_substate(orm.Model):
|
||||||
"""
|
""" To precise a state (state=refused; substates= reason 1, 2,...) """
|
||||||
To precise a state (state=refused; substates= reason 1, 2,...)
|
|
||||||
"""
|
|
||||||
_name = "substate.substate"
|
_name = "substate.substate"
|
||||||
_description = "substate that precise a given state"
|
_description = "substate that precise a given state"
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Sub state', size=128, required=True),
|
'name': fields.char('Sub state', required=True),
|
||||||
'substate_descr' : fields.text('Description',
|
'substate_descr': fields.text(
|
||||||
help="To give more information about the sub state"),
|
'Description',
|
||||||
# ADD OBJECT TO FILTER
|
help="To give more information about the sub state"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class claim_line(orm.Model):
|
class claim_line(orm.Model):
|
||||||
@@ -50,18 +46,19 @@ class claim_line(orm.Model):
|
|||||||
"""
|
"""
|
||||||
_name = "claim.line"
|
_name = "claim.line"
|
||||||
_description = "List of product to return"
|
_description = "List of product to return"
|
||||||
|
|
||||||
# Comment written in a claim.line to know about the warranty status
|
# Comment written in a claim.line to know about the warranty status
|
||||||
WARRANT_COMMENT = {
|
WARRANT_COMMENT = {
|
||||||
'valid': "Valid",
|
'valid': "Valid",
|
||||||
'expired': "Expired",
|
'expired': "Expired",
|
||||||
'not_define': "Not Defined"}
|
'not_define': "Not Defined"}
|
||||||
|
|
||||||
# Method to calculate total amount of the line : qty*UP
|
# Method to calculate total amount of the line : qty*UP
|
||||||
def _line_total_amount(self, cr, uid, ids, field_name, arg, context=None):
|
def _line_total_amount(self, cr, uid, ids, field_name, arg, context=None):
|
||||||
res = {}
|
res = {}
|
||||||
for line in self.browse(cr,uid,ids):
|
for line in self.browse(cr, uid, ids, context=context):
|
||||||
res[line.id] = line.unit_sale_price*line.product_returned_quantity
|
res[line.id] = (line.unit_sale_price *
|
||||||
|
line.product_returned_quantity)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def copy_data(self, cr, uid, id, default=None, context=None):
|
def copy_data(self, cr, uid, id, default=None, context=None):
|
||||||
@@ -75,134 +72,158 @@ class claim_line(orm.Model):
|
|||||||
std_default.update(default)
|
std_default.update(default)
|
||||||
return super(claim_line, self).copy_data(
|
return super(claim_line, self).copy_data(
|
||||||
cr, uid, id, default=std_default, context=context)
|
cr, uid, id, default=std_default, context=context)
|
||||||
|
|
||||||
def get_warranty_return_partner(self, cr, uid, context=None):
|
def get_warranty_return_partner(self, cr, uid, context=None):
|
||||||
seller = self.pool.get('product.supplierinfo')
|
seller = self.pool.get('product.supplierinfo')
|
||||||
result = seller.get_warranty_return_partner(cr, uid, context=context)
|
result = seller.get_warranty_return_partner(cr, uid, context=context)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Description', size=64,required=True),
|
'name': fields.char('Description', required=True),
|
||||||
'claim_origine': fields.selection([('none','Not specified'),
|
'claim_origine': fields.selection(
|
||||||
('legal','Legal retractation'),
|
[('none', 'Not specified'),
|
||||||
('cancellation','Order cancellation'),
|
('legal', 'Legal retractation'),
|
||||||
('damaged','Damaged delivered product'),
|
('cancellation', 'Order cancellation'),
|
||||||
('error','Shipping error'),
|
('damaged', 'Damaged delivered product'),
|
||||||
('exchange','Exchange request'),
|
('error', 'Shipping error'),
|
||||||
('lost','Lost during transport'),
|
('exchange', 'Exchange request'),
|
||||||
('other','Other')],
|
('lost', 'Lost during transport'),
|
||||||
|
('other', 'Other')
|
||||||
|
],
|
||||||
'Claim Subject',
|
'Claim Subject',
|
||||||
required=True,
|
required=True,
|
||||||
help="To describe the line product problem"),
|
help="To describe the line product problem"),
|
||||||
'claim_descr' : fields.text('Claim description',
|
'claim_descr': fields.text(
|
||||||
help="More precise description of the problem"),
|
'Claim description',
|
||||||
'product_id': fields.many2one('product.product', 'Product',
|
help="More precise description of the problem"),
|
||||||
|
'product_id': fields.many2one(
|
||||||
|
'product.product',
|
||||||
|
string='Product',
|
||||||
help="Returned product"),
|
help="Returned product"),
|
||||||
'product_returned_quantity' : fields.float('Quantity', digits=(12,2),
|
'product_returned_quantity': fields.float(
|
||||||
|
'Quantity', digits=(12, 2),
|
||||||
help="Quantity of product returned"),
|
help="Quantity of product returned"),
|
||||||
'unit_sale_price' : fields.float('Unit sale price', digits=(12,2),
|
'unit_sale_price' : fields.float(
|
||||||
help="Unit sale price of the product. Auto filed if retrun done by"
|
'Unit sale price', digits=(12, 2),
|
||||||
" invoice selection. BE CAREFUL AND CHECK the automatic value "
|
help="Unit sale price of the product. Auto filled if retrun done "
|
||||||
"as don't take into account previous refounds, invoice "
|
"by invoice selection. Be careful and check the automatic "
|
||||||
|
"value as don't take into account previous refunds, invoice "
|
||||||
"discount, can be for 0 if product for free,..."),
|
"discount, can be for 0 if product for free,..."),
|
||||||
'return_value' : fields.function(_line_total_amount, method=True,
|
'return_value' : fields.function(
|
||||||
string='Total return',
|
_line_total_amount, string='Total return', type='float',
|
||||||
type='float',
|
|
||||||
help="Quantity returned * Unit sold price",),
|
help="Quantity returned * Unit sold price",),
|
||||||
'prodlot_id': fields.many2one('stock.production.lot', 'Serial/Lot n°',
|
'prodlot_id': fields.many2one(
|
||||||
|
'stock.production.lot',
|
||||||
|
string='Serial/Lot n°',
|
||||||
help="The serial/lot of the returned product"),
|
help="The serial/lot of the returned product"),
|
||||||
'applicable_guarantee': fields.selection(
|
'applicable_guarantee': fields.selection(
|
||||||
[
|
[('us', 'Company'),
|
||||||
('us','Company'),
|
('supplier', 'Supplier'),
|
||||||
('supplier','Supplier'),
|
('brand', 'Brand manufacturer')],
|
||||||
('brand','Brand manufacturer')],
|
|
||||||
'Warranty type'),
|
'Warranty type'),
|
||||||
'guarantee_limit': fields.date('Warranty limit',
|
'guarantee_limit': fields.date(
|
||||||
|
'Warranty limit',
|
||||||
readonly=True,
|
readonly=True,
|
||||||
help="The warranty limit is computed as: invoice date + warranty "
|
help="The warranty limit is computed as: invoice date + warranty "
|
||||||
"defined on selected product."),
|
"defined on selected product."),
|
||||||
'warning': fields.char('Warranty', size=64,
|
'warning': fields.char(
|
||||||
|
'Warranty',
|
||||||
readonly=True,
|
readonly=True,
|
||||||
help="If warranty has expired"),
|
help="If warranty has expired"),
|
||||||
"warranty_type": fields.selection(get_warranty_return_partner,
|
"warranty_type": fields.selection(
|
||||||
|
get_warranty_return_partner,
|
||||||
'Warranty type',
|
'Warranty type',
|
||||||
readonly=True,
|
readonly=True,
|
||||||
help="Who is in charge of the warranty return treatment toward the end customer. "
|
help="Who is in charge of the warranty return treatment towards the end customer. "
|
||||||
"Company will use the current compagny delivery or default address and so on for "
|
"Company will use the current company delivery or default address and so on for "
|
||||||
"supplier and brand manufacturer. Doesn't necessarly mean that the warranty to be "
|
"supplier and brand manufacturer. Does not necessarily mean that the warranty to be "
|
||||||
"applied is the one of the return partner (ie: can be returned to the company and "
|
"applied is the one of the return partner (ie: can be returned to the company and "
|
||||||
"be under the brand warranty"),
|
"be under the brand warranty"),
|
||||||
"warranty_return_partner" : fields.many2one('res.partner',
|
"warranty_return_partner" : fields.many2one(
|
||||||
'Warranty Address',
|
'res.partner',
|
||||||
|
string='Warranty Address',
|
||||||
help="Where the customer has to send back the product(s)"),
|
help="Where the customer has to send back the product(s)"),
|
||||||
'claim_id': fields.many2one('crm.claim', 'Related claim',
|
'claim_id': fields.many2one(
|
||||||
|
'crm.claim', string='Related claim',
|
||||||
help="To link to the case.claim object"),
|
help="To link to the case.claim object"),
|
||||||
'state' : fields.selection([('draft','Draft'),
|
'state' : fields.selection(
|
||||||
('refused','Refused'),
|
[('draft', 'Draft'),
|
||||||
('confirmed','Confirmed, waiting for product'),
|
('refused', 'Refused'),
|
||||||
('in_to_control','Received, to control'),
|
('confirmed', 'Confirmed, waiting for product'),
|
||||||
('in_to_treate','Controlled, to treate'),
|
('in_to_control', 'Received, to control'),
|
||||||
('treated','Treated')], 'State'),
|
('in_to_treate', 'Controlled, to treate'),
|
||||||
'substate_id': fields.many2one('substate.substate', 'Sub state',
|
('treated', 'Treated')],
|
||||||
|
string='State'),
|
||||||
|
'substate_id': fields.many2one(
|
||||||
|
'substate.substate',
|
||||||
|
string='Sub state',
|
||||||
help="Select a sub state to precise the standard state. Example 1: "
|
help="Select a sub state to precise the standard state. Example 1: "
|
||||||
"state = refused; substate could be warranty over, not in "
|
"state = refused; substate could be warranty over, not in "
|
||||||
"warranty, no problem,... . Example 2: state = to treate; "
|
"warranty, no problem,... . Example 2: state = to treate; "
|
||||||
"substate could be to refund, to exchange, to repair,..."),
|
"substate could be to refund, to exchange, to repair,..."),
|
||||||
'last_state_change': fields.date('Last change',
|
'last_state_change': fields.date(
|
||||||
|
string='Last change',
|
||||||
help="To set the last state / substate change"),
|
help="To set the last state / substate change"),
|
||||||
'invoice_line_id': fields.many2one('account.invoice.line',
|
'invoice_line_id': fields.many2one(
|
||||||
'Invoice Line',
|
'account.invoice.line',
|
||||||
|
string='Invoice Line',
|
||||||
help='The invoice line related to the returned product'),
|
help='The invoice line related to the returned product'),
|
||||||
'refund_line_id': fields.many2one('account.invoice.line',
|
'refund_line_id': fields.many2one(
|
||||||
'Refund Line',
|
'account.invoice.line',
|
||||||
|
string='Refund Line',
|
||||||
help='The refund line related to the returned product'),
|
help='The refund line related to the returned product'),
|
||||||
'move_in_id': fields.many2one('stock.move',
|
'move_in_id': fields.many2one(
|
||||||
'Move Line from picking in',
|
'stock.move',
|
||||||
|
string='Move Line from picking in',
|
||||||
help='The move line related to the returned product'),
|
help='The move line related to the returned product'),
|
||||||
'move_out_id': fields.many2one('stock.move',
|
'move_out_id': fields.many2one(
|
||||||
'Move Line from picking out',
|
'stock.move',
|
||||||
|
string='Move Line from picking out',
|
||||||
help='The move line related to the returned product'),
|
help='The move line related to the returned product'),
|
||||||
'location_dest_id': fields.many2one('stock.location',
|
'location_dest_id': fields.many2one(
|
||||||
'Return Stock Location',
|
'stock.location',
|
||||||
|
string='Return Stock Location',
|
||||||
help='The return stock location of the returned product'),
|
help='The return stock location of the returned product'),
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'state': lambda *a: 'draft',
|
'state': 'draft',
|
||||||
'name': lambda *a: 'none',
|
'name': 'none',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Method to calculate warranty limit
|
# Method to calculate warranty limit
|
||||||
def set_warranty_limit(self, cr, uid, ids, claim_line, context=None):
|
def set_warranty_limit(self, cr, uid, ids, claim_line, context=None):
|
||||||
date_invoice = claim_line.invoice_line_id.invoice_id.date_invoice
|
date_invoice = claim_line.invoice_line_id.invoice_id.date_invoice
|
||||||
if date_invoice:
|
if not date_invoice:
|
||||||
warning = _(self.WARRANT_COMMENT['not_define'])
|
raise orm.except_orm(
|
||||||
date_inv_at_server = datetime.strptime(date_invoice,
|
_('Error !'),
|
||||||
DEFAULT_SERVER_DATE_FORMAT)
|
_('Cannot find any date for invoice. '
|
||||||
supplier = claim_line.product_id.seller_ids[0]
|
'Must be a validated invoice.'))
|
||||||
if claim_line.claim_id.claim_type == 'supplier':
|
warning = _(self.WARRANT_COMMENT['not_define'])
|
||||||
waranty_duration = int(supplier.warranty_duration)
|
date_inv_at_server = datetime.strptime(date_invoice,
|
||||||
else:
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
waranty_duration = int(claim_line.product_id.warranty)
|
supplier = claim_line.product_id.seller_ids[0]
|
||||||
limit = (date_inv_at_server +
|
if claim_line.claim_id.claim_type == 'supplier':
|
||||||
relativedelta(months=waranty_duration)).strftime(DEFAULT_SERVER_DATE_FORMAT)
|
warranty_duration = int(supplier.warranty_duration)
|
||||||
# If waranty period was defined
|
|
||||||
if waranty_duration > 0:
|
|
||||||
if limit < claim_line.claim_id.date:
|
|
||||||
warning = _(self.WARRANT_COMMENT['expired'])
|
|
||||||
else:
|
|
||||||
warning = _(self.WARRANT_COMMENT['valid'])
|
|
||||||
self.write(cr,uid,ids,{
|
|
||||||
'guarantee_limit' : limit,
|
|
||||||
'warning' : warning,
|
|
||||||
})
|
|
||||||
else:
|
else:
|
||||||
raise osv.except_osv(_('Error !'),
|
warranty_duration = int(claim_line.product_id.warranty)
|
||||||
_('Cannot find any date for invoice ! Must be a validated invoice !'))
|
limit = date_inv_at_server + relativedelta(months=warranty_duration)
|
||||||
|
# If waranty period was defined
|
||||||
|
if warranty_duration > 0:
|
||||||
|
claim_date = datetime.strptime(claim_line.claim_id.date,
|
||||||
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
if limit < claim_date:
|
||||||
|
warning = _(self.WARRANT_COMMENT['expired'])
|
||||||
|
else:
|
||||||
|
warning = _(self.WARRANT_COMMENT['valid'])
|
||||||
|
self.write(cr, uid, ids,
|
||||||
|
{'guarantee_limit': limit.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||||
|
'warning': warning},
|
||||||
|
context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_destination_location(self, cr, uid, product_id,
|
def get_destination_location(self, cr, uid, product_id,
|
||||||
warehouse_id, context=None):
|
warehouse_id, context=None):
|
||||||
"""Compute and return the destination location ID to take
|
"""Compute and return the destination location ID to take
|
||||||
for a return. Always take 'Supplier' one when return type different
|
for a return. Always take 'Supplier' one when return type different
|
||||||
from company."""
|
from company."""
|
||||||
@@ -220,41 +241,44 @@ class claim_line(orm.Model):
|
|||||||
return location_dest_id
|
return location_dest_id
|
||||||
|
|
||||||
# Method to calculate warranty return address
|
# Method to calculate warranty return address
|
||||||
def set_warranty_return_address(self, cr, uid, ids,
|
def set_warranty_return_address(self, cr, uid, ids, claim_line, context=None):
|
||||||
claim_line, context=None):
|
|
||||||
"""Return the partner to be used as return destination and
|
"""Return the partner to be used as return destination and
|
||||||
the destination stock location of the line in case of return.
|
the destination stock location of the line in case of return.
|
||||||
|
|
||||||
We can have various case here:
|
We can have various case here:
|
||||||
- company or other: return to company partner or crm_return_address_id
|
- company or other: return to company partner or crm_return_address_id
|
||||||
if specified
|
if specified
|
||||||
- supplier: return to the supplier address"""
|
- supplier: return to the supplier address
|
||||||
|
|
||||||
|
"""
|
||||||
return_address = None
|
return_address = None
|
||||||
seller = claim_line.product_id.seller_info_id
|
seller = claim_line.product_id.seller_info_id
|
||||||
claim_company = claim_line.claim_id.company_id
|
claim_company = claim_line.claim_id.company_id
|
||||||
return_address = seller.warranty_return_address.id
|
return_address = seller.warranty_return_address.id
|
||||||
return_type = seller.warranty_return_partner
|
return_type = seller.warranty_return_partner
|
||||||
location_dest_id = self.get_destination_location(cr, uid,
|
location_dest_id = self.get_destination_location(
|
||||||
claim_line.product_id.id,
|
cr, uid, claim_line.product_id.id,
|
||||||
claim_line.claim_id.warehouse_id.id,
|
claim_line.claim_id.warehouse_id.id,
|
||||||
context=context)
|
context=context)
|
||||||
self.write(cr, uid, ids,
|
self.write(cr, uid, ids,
|
||||||
{'warranty_return_partner': return_address,
|
{'warranty_return_partner': return_address,
|
||||||
'warranty_type': return_type,
|
'warranty_type': return_type,
|
||||||
'location_dest_id': location_dest_id})
|
'location_dest_id': location_dest_id},
|
||||||
|
context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Method to calculate warranty limit and address
|
|
||||||
def set_warranty(self, cr, uid, ids, context=None):
|
def set_warranty(self, cr, uid, ids, context=None):
|
||||||
|
""" Calculate warranty limit and address """
|
||||||
for claim_line in self.browse(cr, uid, ids, context=context):
|
for claim_line in self.browse(cr, uid, ids, context=context):
|
||||||
if claim_line.product_id and claim_line.invoice_line_id:
|
if not (claim_line.product_id and claim_line.invoice_line_id):
|
||||||
self.set_warranty_limit(cr, uid, ids,
|
raise orm.except_orm(
|
||||||
claim_line, context=context)
|
_('Error !'),
|
||||||
self.set_warranty_return_address(cr, uid, ids,
|
_('Please set product and invoice.'))
|
||||||
claim_line, context=context)
|
self.set_warranty_limit(cr, uid, ids,
|
||||||
else:
|
claim_line, context=context)
|
||||||
raise osv.except_osv(_('Error !'),
|
self.set_warranty_return_address(cr, uid, ids,
|
||||||
_('PLEASE SET PRODUCT & INVOICE!'))
|
claim_line, context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
#TODO add the option to split the claim_line in order to manage the same product separately
|
#TODO add the option to split the claim_line in order to manage the same product separately
|
||||||
@@ -262,18 +286,22 @@ class crm_claim(orm.Model):
|
|||||||
_inherit = 'crm.claim'
|
_inherit = 'crm.claim'
|
||||||
|
|
||||||
def _get_sequence_number(self, cr, uid, context=None):
|
def _get_sequence_number(self, cr, uid, context=None):
|
||||||
res = self.pool.get('ir.sequence').get(cr, uid,
|
seq_obj = self.pool.get('ir.sequence')
|
||||||
'crm.claim.rma', context=context) or '/'
|
res = seq_obj.get(cr, uid, 'crm.claim.rma', context=context) or '/'
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _get_default_warehouse(self, cr, uid, context=None):
|
def _get_default_warehouse(self, cr, uid, context=None):
|
||||||
company_id = self.pool.get('res.users').browse(cr, uid, uid,
|
user_obj = self.pool.get('res.users')
|
||||||
context=context).company_id.id
|
user = user_obj.browse(cr, uid, uid, context=context)
|
||||||
wh_ids = self.pool.get('stock.warehouse').search(cr, uid,
|
company_id = user.company_id.id
|
||||||
[('company_id','=',company_id)], context=context)
|
wh_obj = self.pool.get('stock.warehouse')
|
||||||
|
wh_ids = wh_obj.search(cr, uid,
|
||||||
|
[('company_id', '=', company_id)],
|
||||||
|
context=context)
|
||||||
if not wh_ids:
|
if not wh_ids:
|
||||||
raise osv.except_osv(_('Error!'),
|
raise orm.except_orm(
|
||||||
_('There is no warehouse for the current user\'s company!'))
|
_('Error!'),
|
||||||
|
_('There is no warehouse for the current user\'s company.'))
|
||||||
return wh_ids[0]
|
return wh_ids[0]
|
||||||
|
|
||||||
def name_get(self, cr, uid, ids, context=None):
|
def name_get(self, cr, uid, ids, context=None):
|
||||||
@@ -283,9 +311,9 @@ class crm_claim(orm.Model):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def create(self, cr, uid, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
if ('number' not in vals) or (vals.get('number')=='/'):
|
if ('number' not in vals) or (vals.get('number') == '/'):
|
||||||
vals['number'] = self._get_sequence_number(cr, uid, context=context)
|
vals['number'] = self._get_sequence_number(cr, uid, context=context)
|
||||||
new_id = super(crm_claim, self).create(cr, uid, vals, context)
|
new_id = super(crm_claim, self).create(cr, uid, vals, context=context)
|
||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
def copy_data(self, cr, uid, id, default=None, context=None):
|
def copy_data(self, cr, uid, id, default=None, context=None):
|
||||||
@@ -301,49 +329,55 @@ class crm_claim(orm.Model):
|
|||||||
cr, uid, id, default=std_default, context=context)
|
cr, uid, id, default=std_default, context=context)
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'number': fields.char('Number', readonly=True,
|
'number': fields.char(
|
||||||
|
'Number', readonly=True,
|
||||||
states={'draft': [('readonly', False)]},
|
states={'draft': [('readonly', False)]},
|
||||||
required=True,
|
required=True,
|
||||||
select=True,
|
select=True,
|
||||||
help="Company internal claim unique number"),
|
help="Company internal claim unique number"),
|
||||||
'claim_type': fields.selection([('customer','Customer'),
|
'claim_type': fields.selection(
|
||||||
('supplier','Supplier'),
|
[('customer', 'Customer'),
|
||||||
('other','Other')],
|
('supplier', 'Supplier'),
|
||||||
'Claim type',
|
('other', 'Other')],
|
||||||
|
string='Claim type',
|
||||||
required=True,
|
required=True,
|
||||||
help="customer = from customer to company ; supplier = from "
|
help="Customer: from customer to company.\n "
|
||||||
"company to supplier"),
|
"Supplier: from company to supplier."),
|
||||||
'claim_line_ids' : fields.one2many('claim.line', 'claim_id',
|
'claim_line_ids': fields.one2many(
|
||||||
'Return lines'),
|
'claim.line', 'claim_id',
|
||||||
|
string='Return lines'),
|
||||||
'planned_revenue': fields.float('Expected revenue'),
|
'planned_revenue': fields.float('Expected revenue'),
|
||||||
'planned_cost': fields.float('Expected cost'),
|
'planned_cost': fields.float('Expected cost'),
|
||||||
'real_revenue': fields.float('Real revenue'),
|
'real_revenue': fields.float('Real revenue'),
|
||||||
'real_cost': fields.float('Real cost'),
|
'real_cost': fields.float('Real cost'),
|
||||||
'invoice_ids': fields.one2many('account.invoice', 'claim_id', 'Refunds'),
|
'invoice_ids': fields.one2many('account.invoice', 'claim_id', 'Refunds'),
|
||||||
'picking_ids': fields.one2many('stock.picking', 'claim_id', 'RMA'),
|
'picking_ids': fields.one2many('stock.picking', 'claim_id', 'RMA'),
|
||||||
'invoice_id': fields.many2one('account.invoice', 'Invoice',
|
'invoice_id': fields.many2one(
|
||||||
|
'account.invoice', string='Invoice',
|
||||||
help='Related original Cusotmer invoice'),
|
help='Related original Cusotmer invoice'),
|
||||||
'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse',
|
'warehouse_id': fields.many2one(
|
||||||
|
'stock.warehouse', string='Warehouse',
|
||||||
required=True),
|
required=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'number': lambda self, cr, uid, context: '/',
|
'number': '/',
|
||||||
'claim_type': 'customer',
|
'claim_type': 'customer',
|
||||||
'warehouse_id': _get_default_warehouse,
|
'warehouse_id': _get_default_warehouse,
|
||||||
}
|
}
|
||||||
|
|
||||||
_sql_constraints = [
|
_sql_constraints = [
|
||||||
('number_uniq', 'unique(number, company_id)', 'Number/Reference must be unique per Company!'),
|
('number_uniq', 'unique(number, company_id)',
|
||||||
|
'Number/Reference must be unique per Company!'),
|
||||||
]
|
]
|
||||||
|
|
||||||
def onchange_partner_address_id(self, cr, uid, ids, add,
|
def onchange_partner_address_id(self, cr, uid, ids, add, email=False, context=None):
|
||||||
email=False, context=None):
|
res = super(crm_claim, self).onchange_partner_address_id(
|
||||||
res = super(crm_claim, self).onchange_partner_address_id(cr, uid, ids,
|
cr, uid, ids, add, email=email)
|
||||||
add, email=email)
|
|
||||||
if add:
|
if add:
|
||||||
if not res['value']['email_from'] or not res['value']['partner_phone']:
|
if not res['value']['email_from'] or not res['value']['partner_phone']:
|
||||||
address = self.pool.get('res.partner').browse(cr, uid, add)
|
partner_obj = self.pool.get('res.partner')
|
||||||
|
address = partner_obj.browse(cr, uid, add, context=context)
|
||||||
for other_add in address.partner_id.address:
|
for other_add in address.partner_id.address:
|
||||||
if other_add.email and not res['value']['email_from']:
|
if other_add.email and not res['value']['email_from']:
|
||||||
res['value']['email_from'] = other_add.email
|
res['value']['email_from'] = other_add.email
|
||||||
@@ -351,29 +385,30 @@ class crm_claim(orm.Model):
|
|||||||
res['value']['partner_phone'] = other_add.phone
|
res['value']['partner_phone'] = other_add.phone
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def onchange_invoice_id(self, cr, uid, ids, invoice_id,
|
def onchange_invoice_id(self, cr, uid, ids, invoice_id, warehouse_id, context=None):
|
||||||
warehouse_id, context=None):
|
|
||||||
invoice_line_obj = self.pool.get('account.invoice.line')
|
invoice_line_obj = self.pool.get('account.invoice.line')
|
||||||
claim_line_obj = self.pool.get('claim.line')
|
claim_line_obj = self.pool.get('claim.line')
|
||||||
invoice_line_ids = invoice_line_obj.search(cr, uid,
|
invoice_line_ids = invoice_line_obj.search(
|
||||||
[('invoice_id','=',invoice_id)])
|
cr, uid,
|
||||||
|
[('invoice_id', '=', invoice_id)],
|
||||||
|
context=context)
|
||||||
claim_lines = []
|
claim_lines = []
|
||||||
if not warehouse_id:
|
if not warehouse_id:
|
||||||
warehouse_id = self._get_default_warehouse(cr, uid, context=context)
|
warehouse_id = self._get_default_warehouse(cr, uid, context=context)
|
||||||
for invoice_line in invoice_line_obj.browse(cr,uid,invoice_line_ids):
|
invoice_lines = invoice_line_obj.browse(cr, uid, invoice_line_ids,
|
||||||
location_dest_id = claim_line_obj.get_destination_location(cr, uid,
|
context=context)
|
||||||
invoice_line.product_id.id,
|
for invoice_line in invoice_lines:
|
||||||
warehouse_id,
|
location_dest_id = claim_line_obj.get_destination_location(
|
||||||
context=context)
|
cr, uid, invoice_line.product_id.id,
|
||||||
|
warehouse_id, context=context)
|
||||||
claim_lines.append({
|
claim_lines.append({
|
||||||
'name': invoice_line.name,
|
'name': invoice_line.name,
|
||||||
'claim_origine' : "none",
|
'claim_origine': "none",
|
||||||
'invoice_line_id': invoice_line.id,
|
'invoice_line_id': invoice_line.id,
|
||||||
'product_id' : invoice_line.product_id.id,
|
'product_id': invoice_line.product_id.id,
|
||||||
'product_returned_quantity' : invoice_line.quantity,
|
'product_returned_quantity': invoice_line.quantity,
|
||||||
'unit_sale_price' : invoice_line.price_unit,
|
'unit_sale_price': invoice_line.price_unit,
|
||||||
'location_dest_id': location_dest_id,
|
'location_dest_id': location_dest_id,
|
||||||
'state' : 'draft',
|
'state': 'draft',
|
||||||
})
|
})
|
||||||
return {'value' : {'claim_line_ids' : claim_lines}}
|
return {'value': {'claim_line_ids': claim_lines}}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
from openerp.osv import fields, orm, osv
|
from openerp.osv import fields, orm
|
||||||
|
|
||||||
|
|
||||||
class stock_picking(orm.Model):
|
class stock_picking(orm.Model):
|
||||||
@@ -30,24 +30,24 @@ class stock_picking(orm.Model):
|
|||||||
'claim_id': fields.many2one('crm.claim', 'Claim'),
|
'claim_id': fields.many2one('crm.claim', 'Claim'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def create(self, cr, user, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
if ('name' not in vals) or (vals.get('name')=='/'):
|
if ('name' not in vals) or (vals.get('name') == '/'):
|
||||||
if vals['type'] != 'internal':
|
sequence_obj = self.pool.get('ir.sequence')
|
||||||
seq_obj_name = 'stock.picking.' + vals['type']
|
if vals['type'] == 'internal':
|
||||||
|
seq_obj_name = self._name
|
||||||
else:
|
else:
|
||||||
seq_obj_name = self._name
|
seq_obj_name = 'stock.picking.' + vals['type']
|
||||||
vals['name'] = self.pool.get('ir.sequence').get(cr, user,
|
vals['name'] = sequence_obj.get(cr, uid, seq_obj_name,
|
||||||
seq_obj_name,
|
context=context)
|
||||||
context=context)
|
new_id = super(stock_picking, self).create(cr, uid, vals,
|
||||||
new_id = super(stock_picking, self).create(cr, user, vals,
|
context=context)
|
||||||
context=context)
|
|
||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
|
|
||||||
class stock_picking_out(orm.Model):
|
class stock_picking_out(orm.Model):
|
||||||
|
|
||||||
_inherit = "stock.picking.out"
|
_inherit = "stock.picking.out"
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'claim_id': fields.many2one('crm.claim', 'Claim'),
|
'claim_id': fields.many2one('crm.claim', 'Claim'),
|
||||||
}
|
}
|
||||||
@@ -56,26 +56,27 @@ class stock_picking_out(orm.Model):
|
|||||||
class stock_picking_out(orm.Model):
|
class stock_picking_out(orm.Model):
|
||||||
|
|
||||||
_inherit = "stock.picking.in"
|
_inherit = "stock.picking.in"
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'claim_id': fields.many2one('crm.claim', 'Claim'),
|
'claim_id': fields.many2one('crm.claim', 'Claim'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#This part concern the case of a wrong picking out. We need to create a new
|
# This part concern the case of a wrong picking out. We need to create a new
|
||||||
#stock_move in a picking already open.
|
# stock_move in a picking already open.
|
||||||
#In order to don't have to confirm the stock_move we override the create and
|
# In order to don't have to confirm the stock_move we override the create and
|
||||||
#confirm it at the creation only for this case
|
# confirm it at the creation only for this case
|
||||||
class stock_move(orm.Model):
|
class stock_move(orm.Model):
|
||||||
|
|
||||||
_inherit = "stock.move"
|
_inherit = "stock.move"
|
||||||
|
|
||||||
def create(self, cr, uid, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
move_id = super(stock_move, self).create(cr, uid, vals, context=context)
|
move_id = super(stock_move, self).create(cr, uid, vals, context=context)
|
||||||
if vals.get('picking_id'):
|
if vals.get('picking_id'):
|
||||||
picking = self.pool.get('stock.picking').browse(cr, uid,
|
picking_obj = self.pool.get('stock.picking')
|
||||||
vals['picking_id'], context=context)
|
picking = picking_obj.browse(cr, uid, vals['picking_id'],
|
||||||
|
context=context)
|
||||||
if picking.claim_id and picking.type == u'in':
|
if picking.claim_id and picking.type == u'in':
|
||||||
move = self.write(cr, uid, move_id, {'state': 'confirmed'},
|
self.write(cr, uid, move_id, {'state': 'confirmed'},
|
||||||
context=context)
|
context=context)
|
||||||
return move_id
|
return move_id
|
||||||
|
|||||||
@@ -19,26 +19,27 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
from openerp.osv import fields, orm
|
from openerp.osv import orm
|
||||||
|
|
||||||
|
|
||||||
class account_invoice_refund(orm.TransientModel):
|
class account_invoice_refund(orm.TransientModel):
|
||||||
|
|
||||||
_inherit = "account.invoice.refund"
|
_inherit = "account.invoice.refund"
|
||||||
|
|
||||||
def compute_refund(self, cr, uid, ids, mode='refund', context=None):
|
def compute_refund(self, cr, uid, ids, mode='refund', context=None):
|
||||||
if context is None: context={}
|
if context is None:
|
||||||
|
context={}
|
||||||
if context.get('invoice_ids'):
|
if context.get('invoice_ids'):
|
||||||
context['active_ids'] = context.get('invoice_ids')
|
context['active_ids'] = context.get('invoice_ids')
|
||||||
return super(account_invoice_refund, self).compute_refund(cr, uid, ids,
|
return super(account_invoice_refund, self).compute_refund(
|
||||||
mode='refund', context=context)
|
cr, uid, ids, mode=mode, context=context)
|
||||||
|
|
||||||
def _get_description(self, cr, uid, context=None):
|
def _get_description(self, cr, uid, context=None):
|
||||||
if context is None: context = {}
|
if context is None:
|
||||||
|
context = {}
|
||||||
description = context.get('description') or ''
|
description = context.get('description') or ''
|
||||||
return description
|
return description
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'description': _get_description,
|
'description': _get_description,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# Copyright 2013 Camptocamp
|
# Copyright 2013 Camptocamp
|
||||||
# Copyright 2009-2013 Akretion,
|
# Copyright 2009-2013 Akretion,
|
||||||
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, Joel Grand-Guillaume
|
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, Joel Grand-Guillaume
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
from openerp.osv import fields, orm, osv
|
from openerp.osv import fields, orm, osv
|
||||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
from openerp import netsvc
|
from openerp import netsvc
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
import time
|
import time
|
||||||
@@ -31,54 +31,62 @@ class claim_make_picking(orm.TransientModel):
|
|||||||
_name = 'claim_make_picking.wizard'
|
_name = 'claim_make_picking.wizard'
|
||||||
_description = 'Wizard to create pickings from claim lines'
|
_description = 'Wizard to create pickings from claim lines'
|
||||||
_columns = {
|
_columns = {
|
||||||
'claim_line_source_location': fields.many2one('stock.location',
|
'claim_line_source_location': fields.many2one(
|
||||||
'Source Location',
|
'stock.location',
|
||||||
|
string='Source Location',
|
||||||
help="Location where the returned products are from.",
|
help="Location where the returned products are from.",
|
||||||
required=True),
|
required=True),
|
||||||
'claim_line_dest_location': fields.many2one('stock.location',
|
'claim_line_dest_location': fields.many2one(
|
||||||
'Dest. Location',
|
'stock.location',
|
||||||
|
string='Dest. Location',
|
||||||
help="Location where the system will stock the returned products.",
|
help="Location where the system will stock the returned products.",
|
||||||
required=True),
|
required=True),
|
||||||
'claim_line_ids': fields.many2many('claim.line',
|
'claim_line_ids': fields.many2many(
|
||||||
|
'claim.line',
|
||||||
'claim_line_picking',
|
'claim_line_picking',
|
||||||
'claim_picking_id',
|
'claim_picking_id',
|
||||||
'claim_line_id',
|
'claim_line_id',
|
||||||
'Claim lines'),
|
string='Claim lines'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_claim_lines(self, cr, uid, context):
|
def _get_claim_lines(self, cr, uid, context):
|
||||||
#TODO use custom states to show buttons of this wizard or not instead of raise an error
|
#TODO use custom states to show buttons of this wizard or not instead of raise an error
|
||||||
if context is None: context = {}
|
if context is None:
|
||||||
|
context = {}
|
||||||
line_obj = self.pool.get('claim.line')
|
line_obj = self.pool.get('claim.line')
|
||||||
if context.get('picking_type') == 'out':
|
if context.get('picking_type') == 'out':
|
||||||
move_field = 'move_out_id'
|
move_field = 'move_out_id'
|
||||||
else:
|
else:
|
||||||
move_field = 'move_in_id'
|
move_field = 'move_in_id'
|
||||||
good_lines = []
|
good_lines = []
|
||||||
line_ids = line_obj.search(cr, uid,
|
line_ids = line_obj.search(
|
||||||
[('claim_id', '=', context['active_id'])], context=context)
|
cr, uid,
|
||||||
|
[('claim_id', '=', context['active_id'])],
|
||||||
|
context=context)
|
||||||
for line in line_obj.browse(cr, uid, line_ids, context=context):
|
for line in line_obj.browse(cr, uid, line_ids, context=context):
|
||||||
if not line[move_field] or line[move_field].state == 'cancel':
|
if not line[move_field] or line[move_field].state == 'cancel':
|
||||||
good_lines.append(line.id)
|
good_lines.append(line.id)
|
||||||
if not good_lines:
|
if not good_lines:
|
||||||
raise osv.except_osv(_('Error !'),
|
raise orm.except_orm(
|
||||||
_('A picking has already been created for this claim !'))
|
_('Error'),
|
||||||
|
_('A picking has already been created for this claim.'))
|
||||||
return good_lines
|
return good_lines
|
||||||
|
|
||||||
# Get default source location
|
# Get default source location
|
||||||
def _get_source_loc(self, cr, uid, context):
|
def _get_source_loc(self, cr, uid, context):
|
||||||
loc_id = False
|
loc_id = False
|
||||||
if context is None: context = {}
|
if context is None:
|
||||||
|
context = {}
|
||||||
warehouse_obj = self.pool.get('stock.warehouse')
|
warehouse_obj = self.pool.get('stock.warehouse')
|
||||||
warehouse_id = context.get('warehouse_id')
|
warehouse_id = context.get('warehouse_id')
|
||||||
if context.get('picking_type') == 'out':
|
if context.get('picking_type') == 'out':
|
||||||
loc_id = warehouse_obj.read(cr, uid,
|
loc_id = warehouse_obj.read(
|
||||||
warehouse_id,
|
cr, uid, warehouse_id,
|
||||||
['lot_stock_id'],
|
['lot_stock_id'],
|
||||||
context=context)['lot_stock_id'][0]
|
context=context)['lot_stock_id'][0]
|
||||||
elif context.get('partner_id'):
|
elif context.get('partner_id'):
|
||||||
loc_id = self.pool.get('res.partner').read(cr, uid,
|
loc_id = self.pool.get('res.partner').read(
|
||||||
context['partner_id'],
|
cr, uid, context['partner_id'],
|
||||||
['property_stock_customer'],
|
['property_stock_customer'],
|
||||||
context=context)['property_stock_customer']
|
context=context)['property_stock_customer']
|
||||||
return loc_id
|
return loc_id
|
||||||
@@ -92,7 +100,7 @@ class claim_make_picking(orm.TransientModel):
|
|||||||
for line in line_obj.browse(cr, uid, line_ids, context=context):
|
for line in line_obj.browse(cr, uid, line_ids, context=context):
|
||||||
if line.location_dest_id.id not in line_location:
|
if line.location_dest_id.id not in line_location:
|
||||||
line_location.append(line.location_dest_id.id)
|
line_location.append(line.location_dest_id.id)
|
||||||
if len (line_location) == 1:
|
if len(line_location) == 1:
|
||||||
loc_id = line_location[0]
|
loc_id = line_location[0]
|
||||||
return loc_id
|
return loc_id
|
||||||
|
|
||||||
@@ -103,33 +111,33 @@ class claim_make_picking(orm.TransientModel):
|
|||||||
line_obj = self.pool.get('claim.line')
|
line_obj = self.pool.get('claim.line')
|
||||||
line_partner = []
|
line_partner = []
|
||||||
for line in line_obj.browse(cr, uid, line_ids, context=context):
|
for line in line_obj.browse(cr, uid, line_ids, context=context):
|
||||||
if (line.warranty_return_partner and line.warranty_return_partner.id
|
if (line.warranty_return_partner and line.warranty_return_partner.id
|
||||||
not in line_partner):
|
not in line_partner):
|
||||||
line_partner.append(line.warranty_return_partner.id)
|
line_partner.append(line.warranty_return_partner.id)
|
||||||
if len (line_partner) == 1:
|
if len(line_partner) == 1:
|
||||||
partner_id = line_partner[0]
|
partner_id = line_partner[0]
|
||||||
return partner_id
|
return partner_id
|
||||||
|
|
||||||
# Get default destination location
|
# Get default destination location
|
||||||
def _get_dest_loc(self, cr, uid, context):
|
def _get_dest_loc(self, cr, uid, context):
|
||||||
"""Return the location_id to use as destination.
|
"""Return the location_id to use as destination.
|
||||||
If it's an outoing shippment: take the customer stock property
|
If it's an outoing shippment: take the customer stock property
|
||||||
If it's an incomming shippment take the location_dest_id common to all lines, or
|
If it's an incomming shippment take the location_dest_id common to all lines, or
|
||||||
if different, return None."""
|
if different, return None."""
|
||||||
if context is None: context = {}
|
if context is None:
|
||||||
warehouse_obj = self.pool.get('stock.warehouse')
|
context = {}
|
||||||
warehouse_id = context.get('warehouse_id')
|
|
||||||
loc_id = False
|
loc_id = False
|
||||||
if context.get('picking_type') == 'out' and context.get('partner_id'):
|
if context.get('picking_type') == 'out' and context.get('partner_id'):
|
||||||
loc_id = self.pool.get('res.partner').read(cr, uid,
|
loc_id = self.pool.get('res.partner').read(
|
||||||
context.get('partner_id'),
|
cr, uid, context.get('partner_id'),
|
||||||
['property_stock_customer'],
|
['property_stock_customer'],
|
||||||
context=context)['property_stock_customer'][0]
|
context=context)['property_stock_customer'][0]
|
||||||
elif context.get('picking_type') == 'in' and context.get('partner_id'):
|
elif context.get('picking_type') == 'in' and context.get('partner_id'):
|
||||||
# Add the case of return to supplier !
|
# Add the case of return to supplier !
|
||||||
line_ids = self._get_claim_lines(cr, uid, context=context)
|
line_ids = self._get_claim_lines(cr, uid, context=context)
|
||||||
loc_id = self._get_common_dest_location_from_line(cr, uid,
|
loc_id = self._get_common_dest_location_from_line(cr, uid,
|
||||||
line_ids, context=context)
|
line_ids,
|
||||||
|
context=context)
|
||||||
return loc_id
|
return loc_id
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
@@ -138,13 +146,14 @@ class claim_make_picking(orm.TransientModel):
|
|||||||
'claim_line_ids': _get_claim_lines,
|
'claim_line_ids': _get_claim_lines,
|
||||||
}
|
}
|
||||||
|
|
||||||
def action_cancel(self,cr,uid,ids,conect=None):
|
def action_cancel(self, cr, uid, ids, context=None):
|
||||||
return {'type': 'ir.actions.act_window_close',}
|
return {'type': 'ir.actions.act_window_close'}
|
||||||
|
|
||||||
# If "Create" button pressed
|
# If "Create" button pressed
|
||||||
def action_create_picking(self, cr, uid, ids, context=None):
|
def action_create_picking(self, cr, uid, ids, context=None):
|
||||||
picking_obj = self.pool.get('stock.picking')
|
picking_obj = self.pool.get('stock.picking')
|
||||||
if context is None: context = {}
|
if context is None:
|
||||||
|
context = {}
|
||||||
view_obj = self.pool.get('ir.ui.view')
|
view_obj = self.pool.get('ir.ui.view')
|
||||||
name = 'RMA picking out'
|
name = 'RMA picking out'
|
||||||
if context.get('picking_type') == 'out':
|
if context.get('picking_type') == 'out':
|
||||||
@@ -161,87 +170,96 @@ class claim_make_picking(orm.TransientModel):
|
|||||||
if context.get('picking_type'):
|
if context.get('picking_type'):
|
||||||
note = 'RMA picking ' + str(context.get('picking_type'))
|
note = 'RMA picking ' + str(context.get('picking_type'))
|
||||||
name = note
|
name = note
|
||||||
view_id = view_obj.search(cr, uid, [
|
view_id = view_obj.search(cr, uid,
|
||||||
('xml_id', '=', view_xml_id),
|
[('xml_id', '=', view_xml_id),
|
||||||
('model', '=', 'stock.picking'),
|
('model', '=', 'stock.picking'),
|
||||||
('type', '=', 'form'),
|
('type', '=', 'form'),
|
||||||
('name', '=', view_name)
|
('name', '=', view_name)
|
||||||
], context=context)[0]
|
],
|
||||||
|
context=context)[0]
|
||||||
wizard = self.browse(cr, uid, ids[0], context=context)
|
wizard = self.browse(cr, uid, ids[0], context=context)
|
||||||
claim = self.pool.get('crm.claim').browse(cr, uid,
|
claim = self.pool.get('crm.claim').browse(cr, uid,
|
||||||
context['active_id'], context=context)
|
context['active_id'],
|
||||||
|
context=context)
|
||||||
partner_id = claim.partner_id.id
|
partner_id = claim.partner_id.id
|
||||||
line_ids = [x.id for x in wizard.claim_line_ids]
|
line_ids = [x.id for x in wizard.claim_line_ids]
|
||||||
# In case of product return, we don't allow one picking for various
|
# In case of product return, we don't allow one picking for various
|
||||||
# product if location are different
|
# product if location are different
|
||||||
# or if partner address is different
|
# or if partner address is different
|
||||||
if context.get('product_return'):
|
if context.get('product_return'):
|
||||||
common_dest_loc_id = self._get_common_dest_location_from_line(cr, uid,
|
common_dest_loc_id = self._get_common_dest_location_from_line(
|
||||||
line_ids, context=context)
|
cr, uid, line_ids, context=context)
|
||||||
if not common_dest_loc_id:
|
if not common_dest_loc_id:
|
||||||
raise osv.except_osv(_('Error !'),
|
raise orm.except_orm(
|
||||||
_('A product return cannot be created for various destination location, please '
|
_('Error !'),
|
||||||
'chose line with a same destination location.'))
|
_('A product return cannot be created for various '
|
||||||
common_dest_partner_id = self._get_common_partner_from_line(cr, uid,
|
'destination locations, please choose line with a '
|
||||||
line_ids, context=context)
|
'same destination location.'))
|
||||||
|
common_dest_partner_id = self._get_common_partner_from_line(
|
||||||
|
cr, uid, line_ids, context=context)
|
||||||
if not common_dest_partner_id:
|
if not common_dest_partner_id:
|
||||||
raise osv.except_osv(_('Error !'),
|
raise orm.except_orm(
|
||||||
_('A product return cannot be created for various destination address, please '
|
_('Error !'),
|
||||||
'chose line with a same address.'))
|
_('A product return cannot be created for various '
|
||||||
else:
|
'destination addresses, please choose line with a '
|
||||||
partner_id = common_dest_partner_id
|
'same address.'))
|
||||||
|
partner_id = common_dest_partner_id
|
||||||
# create picking
|
# create picking
|
||||||
picking_id = picking_obj.create(cr, uid, {
|
picking_id = picking_obj.create(
|
||||||
'origin': claim.number,
|
cr, uid,
|
||||||
'type': p_type,
|
{'origin': claim.number,
|
||||||
'move_type': 'one', # direct
|
'type': p_type,
|
||||||
'state': 'draft',
|
'move_type': 'one', # direct
|
||||||
'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
'state': 'draft',
|
||||||
'partner_id': partner_id,
|
'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
||||||
'invoice_state': "none",
|
'partner_id': partner_id,
|
||||||
'company_id': claim.company_id.id,
|
'invoice_state': "none",
|
||||||
'location_id': wizard.claim_line_source_location.id,
|
'company_id': claim.company_id.id,
|
||||||
'location_dest_id': wizard.claim_line_dest_location.id,
|
'location_id': wizard.claim_line_source_location.id,
|
||||||
'note' : note,
|
'location_dest_id': wizard.claim_line_dest_location.id,
|
||||||
'claim_id': claim.id,
|
'note': note,
|
||||||
})
|
'claim_id': claim.id,
|
||||||
|
},
|
||||||
|
context=context)
|
||||||
# Create picking lines
|
# Create picking lines
|
||||||
for wizard_claim_line in wizard.claim_line_ids:
|
for wizard_claim_line in wizard.claim_line_ids:
|
||||||
move_id = self.pool.get('stock.move').create(cr, uid, {
|
move_obj = self.pool.get('stock.move')
|
||||||
'name' : wizard_claim_line.product_id.name_template, # Motif : crm id ? stock_picking_id ?
|
move_id = move_obj.create(
|
||||||
'priority': '0',
|
cr, uid,
|
||||||
#'create_date':
|
{'name': wizard_claim_line.product_id.name_template,
|
||||||
'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
'priority': '0',
|
||||||
'date_expected': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
||||||
'product_id': wizard_claim_line.product_id.id,
|
'date_expected': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
||||||
'product_qty': wizard_claim_line.product_returned_quantity,
|
'product_id': wizard_claim_line.product_id.id,
|
||||||
'product_uom': wizard_claim_line.product_id.uom_id.id,
|
'product_qty': wizard_claim_line.product_returned_quantity,
|
||||||
'partner_id': partner_id,
|
'product_uom': wizard_claim_line.product_id.uom_id.id,
|
||||||
'prodlot_id': wizard_claim_line.prodlot_id.id,
|
'partner_id': partner_id,
|
||||||
# 'tracking_id':
|
'prodlot_id': wizard_claim_line.prodlot_id.id,
|
||||||
'picking_id': picking_id,
|
'picking_id': picking_id,
|
||||||
'state': 'draft',
|
'state': 'draft',
|
||||||
'price_unit': wizard_claim_line.unit_sale_price,
|
'price_unit': wizard_claim_line.unit_sale_price,
|
||||||
# 'price_currency_id': claim_id.company_id.currency_id.id, # from invoice ???
|
'company_id': claim.company_id.id,
|
||||||
'company_id': claim.company_id.id,
|
'location_id': wizard.claim_line_source_location.id,
|
||||||
'location_id': wizard.claim_line_source_location.id,
|
'location_dest_id': wizard.claim_line_dest_location.id,
|
||||||
'location_dest_id': wizard.claim_line_dest_location.id,
|
'note': note,
|
||||||
'note': note,
|
},
|
||||||
})
|
context=context)
|
||||||
self.pool.get('claim.line').write(cr, uid,
|
self.pool.get('claim.line').write(
|
||||||
wizard_claim_line.id, {write_field: move_id}, context=context)
|
cr, uid, wizard_claim_line.id,
|
||||||
|
{write_field: move_id}, context=context)
|
||||||
wf_service = netsvc.LocalService("workflow")
|
wf_service = netsvc.LocalService("workflow")
|
||||||
if picking_id:
|
if picking_id:
|
||||||
wf_service.trg_validate(uid, 'stock.picking',
|
wf_service.trg_validate(uid, 'stock.picking',
|
||||||
picking_id,'button_confirm', cr)
|
picking_id, 'button_confirm', cr)
|
||||||
picking_obj.action_assign(cr, uid, [picking_id])
|
picking_obj.action_assign(cr, uid, [picking_id])
|
||||||
domain = "[('type','=','%s'),('partner_id','=',%s)]"%(p_type, partner_id)
|
domain = ("[('type', '=', '%s'), ('partner_id', '=', %s)]" %
|
||||||
|
(p_type, partner_id))
|
||||||
return {
|
return {
|
||||||
'name': '%s' % name,
|
'name': '%s' % name,
|
||||||
'view_type': 'form',
|
'view_type': 'form',
|
||||||
'view_mode': 'form',
|
'view_mode': 'form',
|
||||||
'view_id': view_id,
|
'view_id': view_id,
|
||||||
'domain' : domain,
|
'domain': domain,
|
||||||
'res_model': 'stock.picking',
|
'res_model': 'stock.picking',
|
||||||
'res_id': picking_id,
|
'res_id': picking_id,
|
||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
|
|||||||
Reference in New Issue
Block a user