Skip to content

[FIX] when deleting a build, kill its instance #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion runbot/runbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,16 @@ def cron(self, cr, uid, ids=None, context=None):
self.scheduler(cr, uid, ids, context=context)
self.reload_nginx(cr, uid, context=context)

def unlink(self, cr, uid, ids, context=None):
# ondelete=cascade works on database level, but we want
# runbot.build#unlink to execute
branch_obj = self.pool['runbot.branch']
branch_obj.unlink(
cr, uid, branch_obj.search(cr, uid, [('repo_id', 'in', ids)],
context=context),
context=context)
return super(runbot_repo, self).unlink(cr, uid, ids, context=context)

class runbot_branch(osv.osv):
_name = "runbot.branch"
_order = 'name'
Expand Down Expand Up @@ -498,6 +508,15 @@ def _is_on_remote(self, cr, uid, ids, context=None):
return False
return True

def unlink(self, cr, uid, ids, context=None):
# ondelete=cascade works on database level, but we want
# runbot.build#unlink to execute
build_obj = self.pool['runbot.build']
build_obj.unlink(
cr, uid, build_obj.search(cr, uid, [('branch_id', 'in', ids)],
context=context),
context=context)
return super(runbot_branch, self).unlink(cr, uid, ids, context=context)

class runbot_build(osv.osv):
_name = "runbot.build"
Expand Down Expand Up @@ -1126,7 +1145,7 @@ def schedule(self, cr, uid, ids, context=None):
build._local_cleanup()

def skip(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state': 'done', 'result': 'skipped'}, context=context)
self.kill(cr, uid, ids, result='skipped', context=context)
to_unduplicate = self.search(cr, uid, [('id', 'in', ids), ('duplicate_id', '!=', False)])
if len(to_unduplicate):
self.force(cr, uid, to_unduplicate, context=context)
Expand All @@ -1148,7 +1167,11 @@ def _local_cleanup(self, cr, uid, ids, context=None):
# cleanup: find any build older than 7 days.
root = self.pool['runbot.repo'].root(cr, uid)
build_dir = os.path.join(root, 'build')
if not os.path.exists(build_dir):
return
builds = os.listdir(build_dir)
if not builds:
return
cr.execute("""
SELECT dest
FROM runbot_build
Expand All @@ -1164,6 +1187,8 @@ def _local_cleanup(self, cr, uid, ids, context=None):

def kill(self, cr, uid, ids, result=None, context=None):
for build in self.browse(cr, uid, ids, context=context):
if not build.pid:
continue
build._log('kill', 'Kill build %s' % build.dest)
build.logger('killing %s', build.pid)
try:
Expand Down Expand Up @@ -1202,6 +1227,10 @@ def _log(self, cr, uid, ids, func, message, context=None):
'line': '0',
}, context=context)

def unlink(self, cr, uid, ids, context=None):
self.kill(cr, uid, ids, result='killed', context=context)
return super(runbot_build, self).unlink(cr, uid, ids, context=context)

class runbot_event(osv.osv):
_inherit = 'ir.logging'
_order = 'id'
Expand Down
4 changes: 4 additions & 0 deletions stock_picking_refund/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import models
23 changes: 23 additions & 0 deletions stock_picking_refund/__openerp__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

{
'name': 'Decrease delivred quantity',
'version': '1.0',
'category': 'Stock',
'description': """
This allows to decrease the quantity delivered in the
associated SO, and therefore to generate refunds more easily.
==============================================================
""",
'depends': ['sale_stock'],
'data': [
'security/ir.model.access.csv',
'views/sale_stock_view.xml',

],
'demo': [],
'test': [],
'installable': True,
'auto_install': False,
}
2 changes: 2 additions & 0 deletions stock_picking_refund/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
import sale_stock
45 changes: 45 additions & 0 deletions stock_picking_refund/models/sale_stock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from openerp import api, fields, models


class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'

@api.multi
def _get_delivered_qty(self):
"""Computes the delivered quantity on sale order lines, based on done stock moves related to its procurements
"""
self.ensure_one()
qty = super(SaleOrderLine, self)._get_delivered_qty()
for move in self.procurement_ids.mapped('move_ids').filtered(lambda r: r.state == 'done' and not r.scrapped):
if move.location_dest_id.usage == "internal" and move.to_refund_so:
qty -= self.env['product.uom']._compute_qty_obj(move.product_uom, move.product_uom_qty, self.product_uom)
return qty

class StockMove(models.Model):
_inherit = "stock.move"

to_refund_so = fields.Boolean(string="To Refund in SO", default=False,
help='Trigger a decrease of the delivered quantity in the associated Sale Order')

class StockReturnPicking(models.TransientModel):
_inherit = "stock.return.picking"

@api.multi
def _create_returns(self):
new_picking_id, pick_type_id = super(StockReturnPicking, self)._create_returns()
new_picking = self.env['stock.picking'].browse([new_picking_id])
for move in new_picking.move_lines:
return_picking_line = self.product_return_moves.filtered(lambda r: r.move_id == move.origin_returned_move_id)
if return_picking_line and return_picking_line.to_refund_so:
move.to_refund_so = True

return new_picking_id, pick_type_id


class StockReturnPickingLine(models.TransientModel):
_inherit = "stock.return.picking.line"

to_refund_so = fields.Boolean(string="To Refund in SO", help='Trigger a decrease of the delivered quantity in the associated Sale Order')
1 change: 1 addition & 0 deletions stock_picking_refund/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
67 changes: 67 additions & 0 deletions stock_picking_refund/tests/test_sale_stock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp.addons.sale.tests.test_sale_common import TestSale


class TestSaleStock(TestSale):
def test_00_sale_stock_return(self):
"""
Test a SO with a product invoiced on delivery. Deliver and invoice the SO, then do a return
of the picking. Check that a refund invoice is well generated.
"""
# intial so
self.partner = self.env.ref('base.res_partner_1')
self.product = self.env.ref('product.product_delivery_01')
so_vals = {
'partner_id': self.partner.id,
'partner_invoice_id': self.partner.id,
'partner_shipping_id': self.partner.id,
'order_line': [(0, 0, {
'name': self.product.name,
'product_id': self.product.id,
'product_uom_qty': 5.0,
'product_uom': self.product.uom_id.id,
'price_unit': self.product.list_price})],
'pricelist_id': self.env.ref('product.list0').id,
}
self.so = self.env['sale.order'].create(so_vals)

# confirm our standard so
self.so.action_confirm()

# deliver completely
pick = self.so.picking_ids
pick.force_assign()
pick.pack_operation_product_ids.write({'qty_done': 5})
pick.do_new_transfer()

# Create invoice
inv_1_id = self.so.action_invoice_create()
self.inv_1 = self.env['account.invoice'].browse(inv_1_id)
self.inv_1.signal_workflow('invoice_open')

# Create return picking
stockreturnpicking = self.env['stock.return.picking']
default_data = stockreturnpicking.with_context(active_ids=pick.ids, active_id=pick.ids[0]).default_get(['move_dest_exists', 'original_location_id', 'product_return_moves', 'parent_location_id', 'location_id'])
return_wiz = stockreturnpicking.with_context(active_ids=pick.ids, active_id=pick.ids[0]).create(default_data)
return_wiz.product_return_moves.quantity = 2.0 # Return only 2
return_wiz.product_return_moves.to_refund_so = True # Refund these 2
res = return_wiz.create_returns()
return_pick = self.env['stock.picking'].browse(res['res_id'])

# Validate picking
return_pick.force_assign()
return_pick.pack_operation_product_ids.write({'qty_done': 2})
return_pick.do_new_transfer()

# Check invoice
self.assertEqual(self.so.invoice_status, 'to invoice', 'Sale Stock: so invoice_status should be "to invoice" instead of "%s" after picking return' % self.so.invoice_status)
self.assertEqual(self.so.order_line[0].qty_delivered, 3.0, 'Sale Stock: delivered quantity should be 3.0 instead of "%s" after picking return' % self.so.order_line[0].qty_delivered)
# let's do an invoice with refunds
adv_wiz = self.env['sale.advance.payment.inv'].with_context(active_ids=[self.so.id]).create({
'advance_payment_method': 'all',
})
adv_wiz.with_context(open_invoices=True).create_invoices()
self.inv_2 = self.so.invoice_ids.filtered(lambda r: r.state == 'draft')
self.assertEqual(self.inv_2.invoice_line_ids[0].quantity, 2.0, 'Sale Stock: refund quantity on the invoice should be 2.0 instead of "%s".' % self.inv_2.invoice_line_ids[0].quantity)
self.assertEqual(self.so.invoice_status, 'no', 'Sale Stock: so invoice_status should be "no" instead of "%s" after invoicing the return' % self.so.invoice_status)
17 changes: 17 additions & 0 deletions stock_picking_refund/views/sale_stock_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<openerp>
<data>

<record id="view_stock_return_picking_form_inherit_sale_stock" model="ir.ui.view">
<field name="name">stock.return.picking.sale.stock.form</field>
<field name="inherit_id" ref="stock.view_stock_return_picking_form"/>
<field name="model">stock.return.picking</field>
<field name="arch" type="xml">
<field name="quantity" position="after">
<field name="to_refund_so"/>
</field>
</field>
</record>

</data>
</openerp>