mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[IMP] rma_sale: Release 13.0.1.2.0! Add additional support for Sale Warranty return/exchange.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Hibou RMAs for Sale Orders',
|
'name': 'Hibou RMAs for Sale Orders',
|
||||||
'version': '13.0.1.1.0',
|
'version': '13.0.1.2.0',
|
||||||
'category': 'Sale',
|
'category': 'Sale',
|
||||||
'author': 'Hibou Corp.',
|
'author': 'Hibou Corp.',
|
||||||
'license': 'OPL-1',
|
'license': 'OPL-1',
|
||||||
|
|||||||
@@ -14,3 +14,13 @@ class ProductTemplate(models.Model):
|
|||||||
'A positive number will allow the product to be '
|
'A positive number will allow the product to be '
|
||||||
'returned up to that number of days. A negative '
|
'returned up to that number of days. A negative '
|
||||||
'number prevents the return of the product.')
|
'number prevents the return of the product.')
|
||||||
|
|
||||||
|
rma_sale_warranty_validity = fields.Integer(string='RMA Eligible Days (Sale Warranty)',
|
||||||
|
help='Determines the number of days from the time '
|
||||||
|
'of the sale that the product is eligible to '
|
||||||
|
'be returned for warranty claims. '
|
||||||
|
'0 (default) will allow the product to be '
|
||||||
|
'returned for an indefinite period of time. '
|
||||||
|
'A positive number will allow the product to be '
|
||||||
|
'returned up to that number of days. A negative '
|
||||||
|
'number prevents the return of the product.')
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ class RMATemplate(models.Model):
|
|||||||
_inherit = 'rma.template'
|
_inherit = 'rma.template'
|
||||||
|
|
||||||
usage = fields.Selection(selection_add=[('sale_order', 'Sale Order')])
|
usage = fields.Selection(selection_add=[('sale_order', 'Sale Order')])
|
||||||
|
sale_order_warranty = fields.Boolean(string='Sale Order Warranty',
|
||||||
|
help='Determines if the regular return validity or '
|
||||||
|
'Warranty validity is used.')
|
||||||
so_decrement_order_qty = fields.Boolean(string='SO Decrement Ordered Qty.',
|
so_decrement_order_qty = fields.Boolean(string='SO Decrement Ordered Qty.',
|
||||||
help='When completing the RMA, the Ordered Quantity will be decremented by '
|
help='When completing the RMA, the Ordered Quantity will be decremented by '
|
||||||
'the RMA qty.')
|
'the RMA qty.')
|
||||||
@@ -87,7 +90,10 @@ class RMATemplate(models.Model):
|
|||||||
return super(RMATemplate, self)._portal_values(request_user, res_id=res_id)
|
return super(RMATemplate, self)._portal_values(request_user, res_id=res_id)
|
||||||
|
|
||||||
def _rma_sale_line_validity(self, so_line):
|
def _rma_sale_line_validity(self, so_line):
|
||||||
validity_days = so_line.product_id.rma_sale_validity
|
if self.sale_order_warranty:
|
||||||
|
validity_days = so_line.product_id.rma_sale_warranty_validity
|
||||||
|
else:
|
||||||
|
validity_days = so_line.product_id.rma_sale_validity
|
||||||
if validity_days < 0:
|
if validity_days < 0:
|
||||||
return ''
|
return ''
|
||||||
elif validity_days > 0:
|
elif validity_days > 0:
|
||||||
@@ -195,6 +201,10 @@ class RMA(models.Model):
|
|||||||
pass
|
pass
|
||||||
return sale_orders.mapped('invoice_ids') - original_invoices
|
return sale_orders.mapped('invoice_ids') - original_invoices
|
||||||
|
|
||||||
|
def _invoice_values_sale_order(self):
|
||||||
|
# the RMA invoice API will not be used as invoicing will happen at the SO level
|
||||||
|
return False
|
||||||
|
|
||||||
def action_add_so_lines(self):
|
def action_add_so_lines(self):
|
||||||
make_line_obj = self.env['rma.sale.make.lines']
|
make_line_obj = self.env['rma.sale.make.lines']
|
||||||
for rma in self:
|
for rma in self:
|
||||||
|
|||||||
@@ -171,3 +171,136 @@ class TestRMASale(TestRMA):
|
|||||||
# RMA cannot be completed because the inbound picking state is confirmed
|
# RMA cannot be completed because the inbound picking state is confirmed
|
||||||
with self.assertRaises(UserError):
|
with self.assertRaises(UserError):
|
||||||
rma2.action_done()
|
rma2.action_done()
|
||||||
|
|
||||||
|
def test_30_product_sale_return_warranty(self):
|
||||||
|
self.template_sale_return.write({
|
||||||
|
'usage': 'sale_order',
|
||||||
|
'invoice_done': True,
|
||||||
|
'sale_order_warranty': True,
|
||||||
|
'in_to_refund': True,
|
||||||
|
'so_decrement_order_qty': False, # invoice on decremented delivered not decremented order
|
||||||
|
'next_rma_template_id': self.template_rtv.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
validity = 100 # eligible for 100 days
|
||||||
|
warranty_validity = validity + 100 # eligible for 200 days
|
||||||
|
|
||||||
|
self.product1.write({
|
||||||
|
'rma_sale_validity': validity,
|
||||||
|
'rma_sale_warranty_validity': warranty_validity,
|
||||||
|
'type': 'product',
|
||||||
|
'invoice_policy': 'delivery',
|
||||||
|
'tracking': 'serial',
|
||||||
|
'standard_price': 1.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
order = self.env['sale.order'].create({
|
||||||
|
'partner_id': self.partner1.id,
|
||||||
|
'partner_invoice_id': self.partner1.id,
|
||||||
|
'partner_shipping_id': self.partner1.id,
|
||||||
|
'user_id': self.user1.id,
|
||||||
|
'order_line': [(0, 0, {
|
||||||
|
'product_id': self.product1.id,
|
||||||
|
'product_uom_qty': 1.0,
|
||||||
|
'product_uom': self.product1.uom_id.id,
|
||||||
|
'price_unit': 10.0,
|
||||||
|
})]
|
||||||
|
})
|
||||||
|
order.action_confirm()
|
||||||
|
self.assertTrue(order.state in ('sale', 'done'))
|
||||||
|
self.assertEqual(len(order.picking_ids), 1, 'Tests only run with single stage delivery.')
|
||||||
|
|
||||||
|
# Try to RMA item not delivered yet
|
||||||
|
rma = self.env['rma.rma'].create({
|
||||||
|
'template_id': self.template_sale_return.id,
|
||||||
|
'partner_id': self.partner1.id,
|
||||||
|
'partner_shipping_id': self.partner1.id,
|
||||||
|
'sale_order_id': order.id,
|
||||||
|
})
|
||||||
|
self.assertEqual(rma.state, 'draft')
|
||||||
|
# Do not allow warranty return.
|
||||||
|
self.product1.rma_sale_warranty_validity = -1
|
||||||
|
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||||
|
self.assertEqual(wizard.line_ids.qty_delivered, 0.0)
|
||||||
|
wizard.line_ids.product_uom_qty = 1.0
|
||||||
|
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
wizard.add_lines()
|
||||||
|
|
||||||
|
# Allows returns, but not forever
|
||||||
|
self.product1.rma_sale_warranty_validity = warranty_validity
|
||||||
|
original_date_order = order.date_order
|
||||||
|
order.write({'date_order': original_date_order - timedelta(days=warranty_validity+1)})
|
||||||
|
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||||
|
self.assertEqual(wizard.line_ids.qty_delivered, 0.0)
|
||||||
|
wizard.line_ids.product_uom_qty = 1.0
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
wizard.add_lines()
|
||||||
|
|
||||||
|
# Allows returns due to date, due to warranty option
|
||||||
|
order.write({'date_order': original_date_order - timedelta(days=validity+1)})
|
||||||
|
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||||
|
self.assertEqual(wizard.line_ids.qty_delivered, 0.0)
|
||||||
|
wizard.line_ids.product_uom_qty = 1.0
|
||||||
|
wizard.add_lines()
|
||||||
|
|
||||||
|
# finish outbound so that we can invoice.
|
||||||
|
order.picking_ids.action_assign()
|
||||||
|
pack_opt = order.picking_ids.move_line_ids[0]
|
||||||
|
lot = self.env['stock.production.lot'].create({
|
||||||
|
'product_id': self.product1.id,
|
||||||
|
'name': 'X100',
|
||||||
|
'product_uom_id': self.product1.uom_id.id,
|
||||||
|
'company_id': self.env.user.company_id.id,
|
||||||
|
})
|
||||||
|
pack_opt.qty_done = 1.0
|
||||||
|
pack_opt.lot_id = lot
|
||||||
|
order.picking_ids.button_validate()
|
||||||
|
self.assertEqual(order.picking_ids.state, 'done')
|
||||||
|
self.assertEqual(order.order_line.qty_delivered, 1.0)
|
||||||
|
|
||||||
|
# Invoice the order so that only the core product is invoiced at the end...
|
||||||
|
self.assertFalse(order.invoice_ids)
|
||||||
|
wiz = self.env['sale.advance.payment.inv'].with_context(active_ids=order.ids).create({})
|
||||||
|
wiz.create_invoices()
|
||||||
|
order.flush()
|
||||||
|
self.assertTrue(order.invoice_ids)
|
||||||
|
order_invoice = order.invoice_ids
|
||||||
|
|
||||||
|
self.assertEqual(rma.lines.product_id, self.product1)
|
||||||
|
rma.action_confirm()
|
||||||
|
self.assertTrue(rma.in_picking_id)
|
||||||
|
self.assertEqual(rma.in_picking_id.state, 'assigned')
|
||||||
|
pack_opt = rma.in_picking_id.move_line_ids[0]
|
||||||
|
pack_opt.lot_id = lot.id
|
||||||
|
pack_opt.qty_done = 1.0
|
||||||
|
rma.in_picking_id.button_validate()
|
||||||
|
self.assertEqual(rma.in_picking_id.state, 'done')
|
||||||
|
order.flush()
|
||||||
|
# self.assertEqual(order.order_line.qty_delivered, 0.0)
|
||||||
|
rma.action_done()
|
||||||
|
self.assertEqual(rma.state, 'done')
|
||||||
|
order.flush()
|
||||||
|
|
||||||
|
rma_invoice = rma.invoice_ids
|
||||||
|
self.assertTrue(rma_invoice)
|
||||||
|
sale_line = rma_invoice.invoice_line_ids.filtered(lambda l: l.sale_line_ids)
|
||||||
|
so_line = sale_line.sale_line_ids
|
||||||
|
self.assertTrue(sale_line)
|
||||||
|
self.assertEqual(sale_line.price_unit, so_line.price_unit)
|
||||||
|
|
||||||
|
# Invoices do not have their anglo-saxon cost lines until they post
|
||||||
|
order_invoice.post()
|
||||||
|
rma_invoice.post()
|
||||||
|
|
||||||
|
# Find the return to vendor RMA
|
||||||
|
rtv_rma = self.env['rma.rma'].search([('parent_id', '=', rma.id)])
|
||||||
|
self.assertTrue(rtv_rma)
|
||||||
|
self.assertFalse(rtv_rma.out_picking_id)
|
||||||
|
|
||||||
|
wiz = self.env['rma.make.rtv'].with_context(active_model='rma.rma', active_ids=rtv_rma.ids).create({})
|
||||||
|
self.assertTrue(wiz.rma_line_ids)
|
||||||
|
wiz.partner_id = self.partner2
|
||||||
|
wiz.create_batch()
|
||||||
|
self.assertTrue(rtv_rma.out_picking_id)
|
||||||
|
self.assertEqual(rtv_rma.out_picking_id.partner_id, self.partner2)
|
||||||
|
|||||||
@@ -57,8 +57,8 @@
|
|||||||
<t t-set="validity" t-value="rma_template._rma_sale_line_validity(line)"/>
|
<t t-set="validity" t-value="rma_template._rma_sale_line_validity(line)"/>
|
||||||
<div class="row" t-attf-class="row #{'' if validity == 'valid' else 'text-muted'}">
|
<div class="row" t-attf-class="row #{'' if validity == 'valid' else 'text-muted'}">
|
||||||
<div class="col-lg-1 text-center">
|
<div class="col-lg-1 text-center">
|
||||||
<img t-attf-src="/web/image/product.product/#{line.product_id.id}/image_64"
|
<img class="mr4 float-left o_portal_product_img" t-if="line.product_id.image_128" t-att-src="image_data_uri(line.product_id.image_128)" alt="Product Image" width="64"/>
|
||||||
width="64" alt="Product image"></img>
|
<img class="mr4 float-left o_portal_product_img" t-if="not line.product_id.image_128" src="/web/static/src/img/placeholder.png" alt="Product Image" width="64"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3">
|
<div class="col-lg-3">
|
||||||
<span t-esc="line.product_id.name"/>
|
<span t-esc="line.product_id.name"/>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<xpath expr="//page[@name='sales']/group[@name='sale']" position="inside">
|
<xpath expr="//page[@name='sales']/group[@name='sale']" position="inside">
|
||||||
<group name="rma_sale" string="RMA Sales">
|
<group name="rma_sale" string="RMA Sales">
|
||||||
<field name="rma_sale_validity" string="Eligible Days"/>
|
<field name="rma_sale_validity" string="Eligible Days"/>
|
||||||
|
<field name="rma_sale_warranty_validity" string="Warranty Eligible Days"/>
|
||||||
</group>
|
</group>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
<xpath expr="//page[@name='sales']/group[@name='sale']" position="inside">
|
<xpath expr="//page[@name='sales']/group[@name='sale']" position="inside">
|
||||||
<group name="rma_sale" string="RMA Sales">
|
<group name="rma_sale" string="RMA Sales">
|
||||||
<field name="rma_sale_validity" string="Eligible Days"/>
|
<field name="rma_sale_validity" string="Eligible Days"/>
|
||||||
|
<field name="rma_sale_warranty_validity" string="Warranty Eligible Days"/>
|
||||||
</group>
|
</group>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//field[@name='usage']" position="after">
|
<xpath expr="//field[@name='usage']" position="after">
|
||||||
<field name="so_decrement_order_qty" string="Decrement Ordered Qty" attrs="{'invisible': [('usage', '!=', 'sale_order')]}"/>
|
<field name="so_decrement_order_qty" string="Decrement Ordered Qty" attrs="{'invisible': [('usage', '!=', 'sale_order')]}"/>
|
||||||
|
<field name="sale_order_warranty" string="Warranty" attrs="{'invisible': [('usage', '!=', 'sale_order')]}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
Reference in New Issue
Block a user