Merge pull request #47 from vauxoo-dev/8.0-redesign_picking_process_crm_claim_rma

[IMP] crm_claim_rma module adapted to new features with respect to picking in Odoo 8.0
This commit is contained in:
Nhomar Hernández [Vauxoo]
2015-09-22 23:47:09 -05:00
7 changed files with 186 additions and 91 deletions

View File

@@ -81,6 +81,7 @@ Contributors:
'stock',
'crm_claim',
'crm_claim_code',
'crm_claim_type',
'product_warranty',
],
'data': [

View File

@@ -220,10 +220,15 @@ class ClaimLine(models.Model):
if not date_invoice:
raise InvoiceNoDate
warning = _(self.WARRANT_COMMENT['not_define'])
warning = 'not_define'
date_invoice = datetime.strptime(date_invoice,
DEFAULT_SERVER_DATE_FORMAT)
if claim_type == 'supplier':
if isinstance(claim_type, self.env['crm.claim.type'].__class__):
claim_type = claim_type.id
if claim_type == self.env.ref('crm_claim_type.'
'crm_claim_type_supplier').id:
try:
warranty_duration = product.seller_ids[0].warranty_duration
except IndexError:
@@ -236,9 +241,9 @@ class ClaimLine(models.Model):
claim_date = datetime.strptime(claim_date,
DEFAULT_SERVER_DATETIME_FORMAT)
if limit < claim_date:
warning = _(self.WARRANT_COMMENT['expired'])
warning = 'expired'
else:
warning = _(self.WARRANT_COMMENT['valid'])
warning = 'valid'
return {'guarantee_limit': limit.strftime(DEFAULT_SERVER_DATE_FORMAT),
'warning': warning}
@@ -278,7 +283,15 @@ class ClaimLine(models.Model):
for a return. Always take 'Supplier' one when return type different
from company.
"""
location_dest_id = warehouse.lot_stock_id
if isinstance(warehouse, int):
location_dest_id = self.env['stock.warehouse']\
.browse(warehouse).lot_stock_id
else:
location_dest_id = warehouse.lot_stock_id
if isinstance(product, int):
product = self.env['product.product']\
.browse(product)
try:
seller = product.seller_ids[0]
if seller.warranty_return_partner != 'company':
@@ -419,15 +432,6 @@ class CrmClaim(models.Model):
std_default.update(default)
return super(CrmClaim, self).copy_data(std_default)
claim_type = fields.Selection(
[('customer', 'Customer'),
('supplier', 'Supplier'),
('other', 'Other')],
string='Claim type',
required=True,
default='customer',
help="Customer: from customer to company.\n "
"Supplier: from company to supplier.")
claim_line_ids = fields.One2many('claim.line', 'claim_id',
string='Claim lines')
planned_revenue = fields.Float(string='Expected revenue')
@@ -500,11 +504,10 @@ class CrmClaim(models.Model):
}
line.update(warranty_values(invoice_line.invoice_id,
invoice_line.product_id))
claim_lines.append([0, 0, line])
claim_lines.append((0, 0, line))
for line in claim_lines:
value = self._convert_to_cache(
{'claim_line_ids': line}, validate=False)
{'claim_line_ids': claim_lines}, validate=False)
self.update(value)
if self.invoice_id:

View File

@@ -22,7 +22,7 @@
-
!record {model: crm.claim, id: claim_refund}:
name: 'Angry Customer'
claim_type: customer
claim_type: crm_claim_type.crm_claim_type_customer
partner_id: base.res_partner_3
invoice_id: account_invoice_claim_refund
stage_id: crm_claim.stage_claim1
@@ -53,4 +53,5 @@
assert len(refund_line_ids) == 2, "It contains 2 lines, as excepted"
refund_lines = self.pool.get('account.invoice.line').browse(cr, uid, refund_line_ids)
assert ref('product.product_product_4') in [refund_lines[0].product_id.id, refund_lines[1].product_id.id], "First line is checked"
assert ref('product.product_product_5') in [refund_lines[0].product_id.id, refund_lines[1].product_id.id], "Second line is checked"
assert ref('product.product_product_5') in [refund_lines[0].product_id.id, refund_lines[1].product_id.id], "Second line is checked"

View File

@@ -2,6 +2,8 @@
##############################################################################
#
# Author: Yannick Vaucher
# Yanina Aular
# Copyright 2015 Vauxoo
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
@@ -21,16 +23,15 @@
from openerp.tests import common
class test_picking_creation(common.TransactionCase):
class TestPickingCreation(common.TransactionCase):
""" Test the correct pickings are created by the wizard. """
def setUp(self):
super(test_picking_creation, self).setUp()
super(TestPickingCreation, self).setUp()
self.WizardMakePicking = self.env['claim_make_picking.wizard']
self.StockPicking = self.env['stock.picking']
ClaimLine = self.env['claim.line']
Claim = self.env['crm.claim']
self.wizard_make_picking = self.env['claim_make_picking.wizard']
claim = self.env['crm.claim']
self.product_id = self.env.ref('product.product_product_4')
@@ -39,41 +40,44 @@ class test_picking_creation(common.TransactionCase):
self.customer_location_id = self.env.ref(
'stock.stock_location_customers')
sale_order_agrolait_demo = self.env.ref('sale.sale_order_1')
self.assertTrue(sale_order_agrolait_demo.invoice_ids,
"The Order Sale of Agrolait not have Invoice")
invoice_agrolait = sale_order_agrolait_demo.invoice_ids[0]
invoice_agrolait.\
signal_workflow('invoice_open')
# Create the claim with a claim line
self.claim_id = Claim.create(
self.claim_id = claim.create(
{
'name': 'TEST CLAIM',
'number': 'TEST CLAIM',
'claim_type': 'customer',
'code': '/',
'claim_type': self.env.ref('crm_claim_type.'
'crm_claim_type_customer').id,
'delivery_address_id': self.partner_id.id,
'partner_id': self.env.ref('base.res_partner_2').id,
'invoice_id': invoice_agrolait.id,
})
self.claim_id.with_context({'create_lines': True}).\
_onchange_invoice_warehouse_type_date()
self.warehouse_id = self.claim_id.warehouse_id
self.claim_line_id = ClaimLine.create(
{
'name': 'TEST CLAIM LINE',
'claim_origine': 'none',
'product_id': self.product_id.id,
'claim_id': self.claim_id.id,
'location_dest_id': self.warehouse_id.lot_stock_id.id,
})
def test_00_new_product_return(self):
"""Test wizard creates a correct picking for product return
"""
wizard = self.WizardMakePicking.with_context({
wizard = self.wizard_make_picking.with_context({
'active_id': self.claim_id.id,
'partner_id': self.partner_id.id,
'warehouse_id': self.warehouse_id.id,
'picking_type': 'in',
'product_return': True,
}).create({})
wizard.action_create_picking()
self.assertEquals(len(self.claim_id.picking_ids), 1,
"Incorrect number of pickings created")
picking = self.claim_id.picking_ids[0]
self.assertEquals(picking.location_id, self.customer_location_id,
"Incorrect source location")
self.assertEquals(picking.location_dest_id,
@@ -85,8 +89,8 @@ class test_picking_creation(common.TransactionCase):
"""
WizardChangeProductQty = self.env['stock.change.product.qty']
wizard_chg_qty = WizardChangeProductQty.with_context({
wizardchangeproductqty = self.env['stock.change.product.qty']
wizard_chg_qty = wizardchangeproductqty.with_context({
'active_id': self.product_id.id,
}).create({
'product_id': self.product_id.id,
@@ -95,7 +99,7 @@ class test_picking_creation(common.TransactionCase):
wizard_chg_qty.change_product_qty()
wizard = self.WizardMakePicking.with_context({
wizard = self.wizard_make_picking.with_context({
'active_id': self.claim_id.id,
'partner_id': self.partner_id.id,
'warehouse_id': self.warehouse_id.id,
@@ -111,3 +115,30 @@ class test_picking_creation(common.TransactionCase):
"Incorrect source location")
self.assertEquals(picking.location_dest_id, self.customer_location_id,
"Incorrect destination location")
def test_02_new_product_return(self):
"""Test wizard creates a correct picking for product return
"""
company = self.env.ref('base.main_company')
warehouse_obj = self.env['stock.warehouse']
warehouse_rec = \
warehouse_obj.search([('company_id',
'=', company.id)])[0]
wizard = self.wizard_make_picking.with_context({
'active_id': self.claim_id.id,
'partner_id': self.partner_id.id,
'warehouse_id': self.warehouse_id.id,
'picking_type': warehouse_rec.in_type_id.id,
}).create({})
wizard.action_create_picking()
self.assertEquals(len(self.claim_id.picking_ids), 1,
"Incorrect number of pickings created")
picking = self.claim_id.picking_ids[0]
self.assertEquals(picking.location_id, self.customer_location_id,
"Incorrect source location")
self.assertEquals(picking.location_dest_id,
self.warehouse_id.lot_stock_id,
"Incorrect destination location")

View File

@@ -60,9 +60,9 @@
<field name="product_id"/>
<field name="name"/>
<field name="prodlot_id"/>
<field name="warning"/>
<field name="warranty_type"/>
<field name="warranty_return_partner"/>
<field name="warning"/>
<field name="warranty_type"/>
<field name="warranty_return_partner"/>
<button name="set_warranty" string="Compute Waranty" type="object" icon="gtk-justify-fill"/>
<field name="product_returned_quantity"/>
<field name="claim_origine"/>
@@ -260,8 +260,19 @@
action="act_crm_claim_substates"
sequence="2"/>
<record model="ir.ui.view" id="crm_case_claims_form_view">
<field name="name">CRM - Claims Form</field>
<field name="model">crm.claim</field>
<field name="inherit_id" ref="crm_claim_type.crm_case_claims_form_view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='claim_type']" position="attributes">
<attribute name="context">{'create_lines': False}</attribute>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="crm_claim_rma_form_view">
<field name="name">CRM - Claim product return Form</field>
<field name="name">CRM - Claims Form</field>
<field name="model">crm.claim</field>
<field name="inherit_id" ref="crm_claim.crm_case_claims_form_view"/>
<field name="arch" type="xml">
@@ -286,7 +297,6 @@
context="{'invoice_ids': [invoice_id], 'claim_line_ids': claim_line_ids, 'description': name, 'claim_id': id}"/>
</field>
<field name="date_deadline" position="after">
<field name="claim_type" context="{'create_lines': False}"/>
<field name="warehouse_id" context="{'create_lines': False}"/>
</field>
<field name="date" position="replace"/>
@@ -300,49 +310,56 @@
string="Quotation/Sales"
icon="fa-strikethrough"
class="oe_stat_button"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in', ['supplier','other'])]}"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
[%(crm_claim_type.crm_claim_type_supplier)d,%(crm_claim_type.crm_claim_type_other)d])]}"
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
<button name="%(act_crm_claim_rma_invoice_out)d" type="action"
string="Invoices"
icon="fa-pencil-square-o"
class="oe_stat_button"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in', ['supplier','other'])]}"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
[%(crm_claim_type.crm_claim_type_supplier)d,%(crm_claim_type.crm_claim_type_other)d])]}"
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
<button name="%(act_crm_claim_rma_refunds_out)d" type="action"
string="Refunds"
icon="fa-file-text-o"
class="oe_stat_button"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in', ['supplier','other'])]}"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
[%(crm_claim_type.crm_claim_type_supplier)d,%(crm_claim_type.crm_claim_type_other)d])]}"
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
<button name="%(act_crm_claim_rma_invoice_in)d" type="action"
string="Invoices"
icon="fa-pencil-square-o"
class="oe_stat_button"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in', ['customer','other'])]}"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
[%(crm_claim_type.crm_claim_type_customer)d,%(crm_claim_type.crm_claim_type_other)d])]}"
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
<button name="%(act_crm_claim_rma_refunds_in)d" type="action"
string="Refunds"
icon="fa-file-text-o"
class="oe_stat_button"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in', ['customer','other'])]}"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
[%(crm_claim_type.crm_claim_type_customer)d,%(crm_claim_type.crm_claim_type_other)d])]}"
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
<button name="%(act_crm_claim_rma_picking_in)d" type="action"
string="Products"
icon="fa-reply"
class="oe_stat_button"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in', ['supplier','other'])]}"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
[%(crm_claim_type.crm_claim_type_customer)d,%(crm_claim_type.crm_claim_type_other)d])]}"
context="{'search_default_claim_id': active_id,'search_default_user_id':False}"/>
<button name="%(act_crm_claim_rma_picking_out)d" type="action"
string="Deliveries"
icon="fa-truck"
class="oe_stat_button"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in', ['supplier','other'])]}"
attrs="{'invisible': ['|',('partner_id','=', False),('claim_type','in',
[%(crm_claim_type.crm_claim_type_supplier)d,%(crm_claim_type.crm_claim_type_other)d])]}"
context="{'search_default_partner_id': [partner_id],'search_default_user_id':False}"/>
</div>
</xpath>
@@ -369,9 +386,9 @@
<field name="invoice_id" domain="['|',('commercial_partner_id','=',partner_id),('partner_id','=',partner_id)]" context="{'create_lines': True}"/>
<field name="delivery_address_id" context="{'tree_view_ref': 'crm_claim_rma.view_partner_contact_tree', 'search_default_parent_id': partner_id}"/>
</group>
<group>
<div name="serial">
<!-- Place for mass return button from crm_rma_lot_mass_return -->
</group>
</div>
<field
name="claim_line_ids"
nolabel="1"

View File

@@ -23,7 +23,7 @@
##############################################################################
import time
from openerp import models, fields, exceptions, api, workflow, _
from openerp import models, fields, exceptions, api, _
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DT_FORMAT
@@ -38,6 +38,7 @@ class ClaimMakePicking(models.TransientModel):
else return an empty recordset
"""
dests = lines.mapped('location_dest_id')
dests = list(set(dests))
return dests[0] if len(dests) == 1 else self.env['stock.location']
@api.returns('res.partner')
@@ -47,8 +48,10 @@ class ClaimMakePicking(models.TransientModel):
else return an empty recordset
"""
partners = lines.mapped('warranty_return_partner')
partners = list(set(partners))
return partners[0] if len(partners) == 1 else self.env['res.partner']
@api.model
def _default_claim_line_source_location_id(self):
picking_type = self.env.context.get('picking_type')
partner_id = self.env.context.get('partner_id')
@@ -75,6 +78,11 @@ class ClaimMakePicking(models.TransientModel):
picking_type = self.env.context.get('picking_type')
partner_id = self.env.context.get('partner_id')
if isinstance(picking_type, int):
picking_obj = self.env['stock.picking.type']
return picking_obj.browse(picking_type)\
.default_location_dest_id
if picking_type == 'out' and partner_id:
return self.env['res.partner'].browse(
partner_id).property_stock_customer
@@ -91,28 +99,44 @@ class ClaimMakePicking(models.TransientModel):
def _default_claim_line_ids(self):
# TODO use custom states to show buttons of this wizard or not instead
# of raise an error
move_field = ('move_out_id'
if self.env.context.get('picking_type') == 'out'
else 'move_in_id')
domain = [
('claim_id', '=', self.env.context['active_id']),
'|', (move_field, '=', False), (move_field+'.state', '=', 'cancel')
]
lines = self.env['claim.line'].search(domain)
if not lines:
raise exceptions.Warning(
_('Error'),
_('A picking has already been created for this claim.'))
picking_type = self.env.context.get('picking_type')
if isinstance(picking_type, int):
picking_obj = self.env['stock.picking.type']
if picking_obj.\
browse(picking_type).\
code == 'incoming':
picking_type = 'in'
else:
picking_type = 'out'
move_field = ('move_in_id'
if picking_type == 'in'
else 'move_out_id')
domain = [('claim_id', '=', self.env.context['active_id'])]
lines = self.env['claim.line'].\
search(domain)
if lines:
domain = domain + [
'|', (move_field, '=', False),
(move_field+'.state', '=', 'cancel')
]
lines = lines.search(domain)
if not lines:
raise exceptions.Warning(
_('Error'),
_('A picking has already been created for this claim.'))
return lines
claim_line_source_location_id = fields.Many2one(
'stock.location', string='Source Location', required=True,
default=_default_claim_line_source_location_id,
help="Location where the returned products are from.")
claim_line_dest_location_id = fields.Many2one(
'stock.location', string='Dest. Location', required=True,
default=_default_claim_line_dest_location_id,
help="Location where the system will stock the returned products.")
claim_line_ids = fields.Many2many(
'claim.line',
'claim_line_picking',
@@ -165,16 +189,29 @@ class ClaimMakePicking(models.TransientModel):
@api.multi
def action_create_picking(self):
picking_type_code = 'incoming'
write_field = 'move_out_id'
if self.env.context.get('picking_type') == 'out':
picking_type_code = 'outgoing'
context = self._context
picking_type = self.env.context.get('picking_type')
if isinstance(picking_type, int):
picking_obj = self.env['stock.picking.type']
picking_type_rec = picking_obj.browse(picking_type)
if picking_type_rec.code == 'incoming':
picking_type = 'in'
elif picking_type_rec.code == 'outgoing':
picking_type = 'out'
else:
picking_type = 'int'
warehouse_obj = self.env['stock.warehouse']
warehouse_rec = warehouse_obj.browse(context.get('warehouse_id'))
if picking_type == 'out':
picking_type = warehouse_rec.out_type_id
write_field = 'move_out_id'
elif picking_type == 'in':
picking_type = warehouse_rec.in_type_id
write_field = 'move_in_id'
destination_id = self.claim_line_dest_location_id.id
picking_type = self.env['stock.picking.type'].search([
('code', '=', picking_type_code),
('default_location_dest_id', '=', destination_id)
], limit=1)
else:
picking_type = warehouse_rec.int_type_id
write_field = 'move_out_id'
claim = self.env['crm.claim'].browse(self.env.context['active_id'])
partner_id = claim.delivery_address_id.id
@@ -194,7 +231,6 @@ class ClaimMakePicking(models.TransientModel):
'same destination location.'))
claim_lines.auto_set_warranty()
common_dest_partner = self._get_common_partner_from_line(
claim_lines)
if not common_dest_partner:
@@ -215,23 +251,28 @@ class ClaimMakePicking(models.TransientModel):
self._get_picking_line_data(claim, picking, line))
line.write({write_field: move.id})
wf_service = workflow
if picking:
cr, uid = self.env.cr, self.env.uid
wf_service.trg_validate(uid, 'stock.picking',
picking.id, 'button_confirm', cr)
picking.signal_workflow('button_confirm')
picking.action_assign()
domain = [
('picking_type_id.code', '=', picking_type_code),
('partner_id', '=', partner_id)
]
domain = ("[('picking_type_id', '=', %s), ('partner_id', '=', %s)]" %
(picking_type.id, partner_id))
view_obj = self.env['ir.ui.view']
view_id = view_obj.search([('model', '=', 'stock.picking'),
('type', '=', 'form'),
])[0]
return {
'name': self._get_picking_name(),
'view_type': 'form',
'view_mode': 'form',
'view_id': view_id.id,
'domain': domain,
'res_model': 'stock.picking',
'res_id': picking.id,
'type': 'ir.actions.act_window',
}
@api.multi
def action_cancel(self):
return {'type': 'ir.actions.act_window_close'}

View File

@@ -25,11 +25,12 @@
name="action_create_picking" type="object"
class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
<button name="action_cancel"
string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
</record>
<record id="action_claim_picking_in" model="ir.actions.act_window">
<field name="name">Return Products</field>
@@ -38,7 +39,7 @@
<field name="src_model">crm.claim</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="target">new</field>
<field name="context">{'picking_type': 'in','product_return': True}</field>
</record>
@@ -49,7 +50,7 @@
<field name="src_model">crm.claim</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="target">new</field>
<field name="context">{'picking_type': 'out'}</field>
</record>