[14.0][IMP] repair_stock_move: use standard reservation engine.

* Reserve moves in the same way it is done in other
  entities (pickings, MO's...).
* Also give flexibility by alowing to easily force availability.
* Other minor changes.
* Set module as alpha.
This commit is contained in:
Lois Rilo
2021-03-17 18:01:17 +01:00
parent 764db059eb
commit 5e71656ce4
13 changed files with 677 additions and 169 deletions

View File

@@ -0,0 +1,92 @@
=================
Repair Stock Move
=================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github
:target: https://github.com/OCA/manufacture/tree/14.0/repair_stock_move
:alt: OCA/manufacture
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/manufacture-14-0/manufacture-14-0-repair_stock_move
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/129/14.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
The purpose of this module is to modify the behaviour of the repair standard module. Achieving more flexibility in a repair process.
The first change that it applies is the modification of the creation of stock moves in the repair flow:
* Confirm Repair: creates draft stock moves on confirmation of the repair order.
* Start Repair: confirms the stock moves.
* End Repair: completes the stock moves and ends the repair order.
Another feature which this module includes is that it allows to add components during all the different stages of the repair process, which adjusts better to the needs of some businesses.
.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_
**Table of contents**
.. contents::
:local:
Usage
=====
Follow the Odoo standard repair module flow.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/manufacture/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/manufacture/issues/new?body=module:%20repair_stock_move%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* ForgeFlow
Contributors
~~~~~~~~~~~~
* Mateu Griful <mateu.griful@forgeflow.com>
* Lois Rilo <lois.rilo@forgeflow.com>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/manufacture <https://github.com/OCA/manufacture/tree/14.0/repair_stock_move>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -1,5 +1 @@
# Copyright (C) 2017-20 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
from . import models
from .hooks import post_load_hook

View File

@@ -4,8 +4,9 @@
{
"name": "Repair Stock Move",
"version": "14.0.1.0.0",
"development_status": "Alpha",
"license": "LGPL-3",
"category": "RMA",
"category": "Repair",
"summary": "Ongoing Repair Stock Moves Definition in odoo",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/manufacture",
@@ -13,7 +14,6 @@
"data": [
"views/repair_order_views.xml",
],
"post_load": "post_load_hook",
"installable": True,
"application": False,
}

View File

@@ -1,23 +0,0 @@
# Copyright 2021 ForgeFlow, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo.addons.repair.models.repair import Repair
# flake8: noqa: C901
def post_load_hook():
def action_repair_end_new(self):
self.write({"repaired": True})
self.move_id._action_assign()
self.move_id._action_done()
for operation in self.operations:
operation.move_id._action_assign()
operation.move_id._action_done()
vals = {"state": "done"}
if not self.invoice_id and self.invoice_method == "after_repair":
vals["state"] = "2binvoiced"
self.write(vals)
if not hasattr(Repair, "action_repair_end_original"):
Repair.action_repair_end_original = Repair.action_repair_end
Repair.action_repair_end = action_repair_end_new

View File

@@ -24,6 +24,7 @@ class RepairLine(models.Model):
"location_id": self.location_id.id,
"location_dest_id": self.location_dest_id.id,
"repair_id": self.repair_id.id,
"repair_line_id": self.id,
"origin": self.repair_id.name,
"company_id": self.company_id.id,
}
@@ -35,16 +36,19 @@ class RepairLine(models.Model):
res = super().create(vals)
if res and res.repair_id.state == "confirmed":
move = res.create_stock_move()
move._action_confirm()
res.move_id = move
move._set_quantity_done(res.product_uom_qty)
if res and res.repair_id.state == "under_repair":
move = res.create_stock_move()
move._action_confirm()
move._set_quantity_done(res.product_uom_qty)
move._action_assign()
res.move_id = move
return res
def unlink(self):
for rec in self:
rec.move_id.unlink()
return super().unlink()
@api.onchange("product_id")
def _onchange_location(self):
if self.state == "draft":
self.location_id = self.repair_id.location_id
# TODO: write qty - update stock move.
# TODO: default repair location in repair lines.

View File

@@ -1,8 +1,8 @@
# Copyright (C) 2021 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
from odoo import _, fields, models
from odoo.exceptions import ValidationError
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools import float_compare
@@ -13,12 +13,14 @@ class RepairOrder(models.Model):
comodel_name="stock.move",
inverse_name="repair_id",
)
show_check_availability = fields.Boolean(
compute="_compute_show_check_availability",
help="Technical field used to compute whether the button "
"'Check Availability' should be displayed.",
)
ignore_availability = fields.Boolean()
# Make "Parts" editable in more states.
operations = fields.One2many(
comodel_name="repair.line",
inverse_name="repair_id",
string="Parts",
copy=True,
readonly=True,
states={
"draft": [("readonly", False)],
"confirmed": [("readonly", False)],
@@ -26,27 +28,7 @@ class RepairOrder(models.Model):
"ready": [("readonly", False)],
},
)
product_qty = fields.Float(
"Product Quantity",
default=1.0,
digits="Product Unit of Measure",
readonly=True,
required=True,
states={
"draft": [("readonly", False)],
"confirmed": [("readonly", False)],
"under_repair": [("readonly", False)],
"ready": [("readonly", False)],
},
)
fees_lines = fields.One2many(
comodel_name="repair.fee",
inverse_name="repair_id",
string="Operations",
copy=True,
readonly=True,
states={
"draft": [("readonly", False)],
"confirmed": [("readonly", False)],
@@ -55,40 +37,76 @@ class RepairOrder(models.Model):
},
)
def action_validate(self):
res = super().action_validate()
self._check_company()
self.operations._check_company()
self.fees_lines._check_company()
res = {}
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
Move = self.env["stock.move"]
for repair in self:
# Try to create move with the appropriate owner
owner_id = False
available_qty_owner = self.env["stock.quant"]._get_available_quantity(
repair.product_id,
repair.location_id,
repair.lot_id,
strict=True,
@api.depends("state")
def _compute_show_check_availability(self):
for rec in self:
rec.show_check_availability = (
any(
move.state in ("waiting", "confirmed", "partially_available")
and float_compare(
move.product_uom_qty,
0,
precision_rounding=move.product_uom.rounding,
)
for move in rec.stock_move_ids
)
and not rec.ignore_availability
)
if available_qty_owner <= 0.0:
raise ValidationError(
_("There is no stock of product: ") + repair.product_id.display_name
)
if (
float_compare(
available_qty_owner, repair.product_qty, precision_digits=precision
)
>= 0
):
owner_id = repair.partner_id.id
def _create_repair_stock_move(self):
self.ensure_one()
return self.env["stock.move"].create(
{
"name": self.name,
"product_id": self.product_id.id,
"product_uom": self.product_uom.id or self.product_id.uom_id.id,
"product_uom_qty": self.product_qty,
"partner_id": self.address_id.id,
"location_id": self.location_id.id,
"location_dest_id": self.location_id.id,
"repair_id": self.id,
"origin": self.name,
"company_id": self.company_id.id,
}
)
def action_repair_confirm(self):
res = super().action_repair_confirm()
for repair in self:
moves = self.env["stock.move"]
for operation in repair.operations:
move = operation.create_stock_move()
moves |= move
operation.write({"move_id": move.id})
move = repair._create_repair_stock_move()
repair.move_id = move
self.mapped("stock_move_ids")._action_confirm()
return res
def action_assign(self):
self.filtered(lambda r: r.state == "draft").action_repair_start()
moves = self.mapped("stock_move_ids")
moves = moves.filtered(
lambda move: move.state not in ("draft", "cancel", "done")
)
if not moves:
raise UserError(_("Nothing to check the availability for."))
moves._action_assign()
return True
def action_repair_start(self):
res = super().action_repair_start()
self.mapped("stock_move_ids")._action_assign()
return res
def action_force_availability(self):
self.write({"ignore_availability": True})
def _force_qty_done_in_repair_lines(self):
for operation in self.mapped("operations"):
for move in operation.stock_move_ids:
if move.state not in ["confirmed", "waiting", "partially_available"]:
continue
product_qty = move.product_uom._compute_quantity(
operation.product_uom_qty,
move.product_id.uom_id,
@@ -101,69 +119,19 @@ class RepairOrder(models.Model):
strict=False,
)
move._update_reserved_quantity(
product_qty,
product_qty - move.reserved_availability,
available_quantity,
move.location_id,
lot_id=operation.lot_id,
strict=False,
)
move._set_quantity_done(operation.product_uom_qty)
if operation.lot_id:
move.move_line_ids.lot_id = operation.lot_id
moves |= move
operation.write({"move_id": move.id, "state": "draft"})
move = Move.create(
{
"name": repair.name,
"product_id": repair.product_id.id,
"product_uom": repair.product_uom.id or repair.product_id.uom_id.id,
"product_uom_qty": repair.product_qty,
"partner_id": repair.address_id.id,
"location_id": repair.location_id.id,
"location_dest_id": repair.location_id.id,
"move_line_ids": [
(
0,
0,
{
"product_id": repair.product_id.id,
"lot_id": repair.lot_id.id,
"product_uom_qty": 0, # bypass reservation here
"product_uom_id": repair.product_uom.id
or repair.product_id.uom_id.id,
"qty_done": repair.product_qty,
"package_id": False,
"result_package_id": False,
"owner_id": owner_id,
"location_id": repair.location_id.id, # TODO:ownerstuff
"company_id": repair.company_id.id,
"location_dest_id": repair.location_id.id,
},
)
],
"repair_id": repair.id,
"origin": repair.name,
"company_id": repair.company_id.id,
}
)
consumed_lines = moves.mapped("move_line_ids")
produced_lines = move.move_line_ids
moves |= move
produced_lines.write({"consume_line_ids": [(6, 0, consumed_lines.ids)]})
res[repair.id] = move.id
repair.move_id = move
return res
def action_repair_start(self):
super().action_repair_start()
(self.move_id | self.operations.mapped("move_id"))._action_confirm()
def action_open_stock_moves(self):
self.ensure_one()
stock_move_ids = self.move_id.ids + self.operations.move_id.ids
domain = [("id", "in", stock_move_ids)]
domain = [("id", "in", self.mapped("stock_move_ids").ids)]
action = {
"name": _("Stock Moves"),
"view_type": "tree",
@@ -176,9 +144,33 @@ class RepairOrder(models.Model):
return action
def action_repair_cancel(self):
if self.move_id.state != "draft" or self.operations:
raise ValidationError(
_("Unable to cancel repair order due to already generated stock moves.")
)
else:
super().action_repair_cancel()
self.mapped("stock_move_ids")._action_cancel()
return super().action_repair_cancel()
def action_repair_end(self):
if any(r.show_check_availability for r in self):
raise UserError(_("Some related stock moves are not available."))
# I can not everything has been reserved.
self._force_qty_done_in_repair_lines()
for repair in self:
operation_moves = repair.mapped("operations.move_id")
if operation_moves:
consumed_lines = operation_moves.mapped("move_line_ids")
produced_lines = repair.move_id.move_line_ids
operation_moves |= repair.move_id
produced_lines.write({"consume_line_ids": [(6, 0, consumed_lines.ids)]})
self.move_id._set_quantity_done(self.move_id.product_uom_qty)
self.move_id._action_done()
for move in self.mapped("operations.move_id"):
move._set_quantity_done(move.product_uom_qty)
move._action_done()
return super().action_repair_end()
def action_repair_done(self):
self.ensure_one()
if self.stock_move_ids:
# With this module this should always be the case, so this is
# effectively overriding the method.
return {self.id: self.move_id.id}
return super().action_repair_done()

View File

@@ -10,4 +10,5 @@ class StockMove(models.Model):
repair_line_id = fields.Many2one(
comodel_name="repair.line",
string="Repair Line",
ondelete="cascade",
)

View File

@@ -1 +1,2 @@
* Mateu Griful <mateu.griful@forgeflow.com>
* Lois Rilo <lois.rilo@forgeflow.com>

View File

@@ -1,9 +1,9 @@
The purpose of this module is to modify the behaviour of the repair standard module. Achieving more flexibility in a repair process.
The first change that it applies is the modification of the creation of stock moves in the repair flow:
* Confirm Repair: creates draft stock moves on confirmation of the repair order.
* Start Repair: confirms the stock moves.
* End Repair: completes the stock moves and ends the repair order.
Another feature which this module includes is that it allows to add components during all the different stages of the repair process, which adjusts better to the needs of some businesses.

View File

@@ -1,2 +1 @@
Follow the Odoo standard repair module flow.

View File

@@ -0,0 +1,438 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: http://docutils.sourceforge.net/" />
<title>Repair Stock Move</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="repair-stock-move">
<h1 class="title">Repair Stock Move</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Alpha" src="https://img.shields.io/badge/maturity-Alpha-red.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/manufacture/tree/14.0/repair_stock_move"><img alt="OCA/manufacture" src="https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/manufacture-14-0/manufacture-14-0-repair_stock_move"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/129/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>The purpose of this module is to modify the behaviour of the repair standard module. Achieving more flexibility in a repair process.</p>
<p>The first change that it applies is the modification of the creation of stock moves in the repair flow:</p>
<ul class="simple">
<li>Confirm Repair: creates draft stock moves on confirmation of the repair order.</li>
<li>Start Repair: confirms the stock moves.</li>
<li>End Repair: completes the stock moves and ends the repair order.</li>
</ul>
<p>Another feature which this module includes is that it allows to add components during all the different stages of the repair process, which adjusts better to the needs of some businesses.</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
<a class="reference external" href="https://odoo-community.org/page/development-status">More details on development status</a></p>
</div>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<p>Follow the Odoo standard repair module flow.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/manufacture/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/manufacture/issues/new?body=module:%20repair_stock_move%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
<ul class="simple">
<li>Mateu Griful &lt;<a class="reference external" href="mailto:mateu.griful&#64;forgeflow.com">mateu.griful&#64;forgeflow.com</a>&gt;</li>
<li>Lois Rilo &lt;<a class="reference external" href="mailto:lois.rilo&#64;forgeflow.com">lois.rilo&#64;forgeflow.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/manufacture/tree/14.0/repair_stock_move">OCA/manufacture</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -55,6 +55,7 @@ class TestRepairStockMove(common.SavepointCase):
)
# Repair Orders
dest_loc_id = cls.product_1.property_stock_production.id
cls.repair1 = cls.env["repair.order"].create(
{
"address_id": cls.res_partner_address_1.id,
@@ -70,9 +71,9 @@ class TestRepairStockMove(common.SavepointCase):
0,
0,
{
"location_dest_id": cls.product_1.property_stock_production.id,
"location_dest_id": dest_loc_id,
"location_id": cls.stock_location_14.id,
"name": cls.product_1.get_product_multiline_description_sale(),
"name": cls.product_1.display_name,
"product_id": cls.product_2.id,
"product_uom": cls.env.ref("uom.product_uom_unit").id,
"product_uom_qty": 1.0,
@@ -88,7 +89,7 @@ class TestRepairStockMove(common.SavepointCase):
0,
0,
{
"name": cls.service.get_product_multiline_description_sale(),
"name": cls.service.display_name,
"product_id": cls.service.id,
"product_uom_qty": 1.0,
"product_uom": cls.env.ref("uom.product_uom_unit").id,
@@ -106,19 +107,6 @@ class TestRepairStockMove(common.SavepointCase):
def test_stock_move_state(self):
# Validate Repair Order
self.repair1.action_validate()
self.assertEqual(
self.repair1.move_id.state,
"draft",
"Generated stock move state should be draft",
)
for operation in self.repair1.operations:
self.assertEqual(
operation.move_id.state,
"draft",
"Generated stock move state should be draft",
)
# Start Repair
self.repair1.action_repair_start()
self.assertEqual(
self.repair1.move_id.state,
"confirmed",
@@ -130,6 +118,8 @@ class TestRepairStockMove(common.SavepointCase):
"confirmed",
"Generated stock move state should be confirmed",
)
# Start Repair
self.repair1.action_repair_start()
# End Repair
self.repair1.action_repair_end()
self.assertEqual(

View File

@@ -6,8 +6,26 @@
<field name="model">repair.order</field>
<field name="inherit_id" ref="repair.view_repair_order_form" />
<field name="arch" type="xml">
<field name="product_qty" position="replace">
<field name="product_qty" />
<header position="inside">
<button
name="action_assign"
attrs="{'invisible': [('show_check_availability', '=', False)]}"
string="Check Availability"
type="object"
class="oe_highlight"
groups="base.group_user"
/>
<button
name="action_force_availability"
attrs="{'invisible': [('show_check_availability', '=', False)]}"
string="Force Availability"
type="object"
groups="base.group_user"
/>
<field name="show_check_availability" invisible="1" />
</header>
<field name="product_qty" position="attributes">
<attribute name="attrs" />
</field>
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
<button