-
-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
11c868d
commit b30ae9d
Showing
24 changed files
with
1,179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
**This file is going to be generated by oca-gen-addon-readme.** | ||
|
||
*Manual changes will be overwritten.* | ||
|
||
Please provide content in the ``readme`` directory: | ||
|
||
* **DESCRIPTION.rst** (required) | ||
* INSTALL.rst (optional) | ||
* CONFIGURE.rst (optional) | ||
* **USAGE.rst** (optional, highly recommended) | ||
* DEVELOP.rst (optional) | ||
* ROADMAP.rst (optional) | ||
* HISTORY.rst (optional, recommended) | ||
* **CONTRIBUTORS.rst** (optional, highly recommended) | ||
* CREDITS.rst (optional) | ||
|
||
Content of this README will also be drawn from the addon manifest, | ||
from keys such as name, authors, maintainers, development_status, | ||
and license. | ||
|
||
A good, one sentence summary in the manifest is also highly recommended. | ||
|
||
|
||
Automatic changelog generation | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
`HISTORY.rst` can be auto generated using `towncrier <https://pypi.org/project/towncrier>`_. | ||
|
||
Just put towncrier compatible changelog fragments into `readme/newsfragments` | ||
and the changelog file will be automatically generated and updated when a new fragment is added. | ||
|
||
Please refer to `towncrier` documentation to know more. | ||
|
||
NOTE: the changelog will be automatically generated when using `/ocabot merge $option`. | ||
If you need to run it manually, refer to `OCA/maintainer-tools README <https://github.com/OCA/maintainer-tools>`_. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import models | ||
from . import wizard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Copyright (C) 2018 Open Source Integrators | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
{ | ||
"name": "TMS - Sales", | ||
"version": "17.0.1.0.0", | ||
"summary": "Sell transportation management system.", | ||
"category": "TMS", | ||
"author": "Open Source Integrators, Odoo Community Association (OCA)", | ||
"website": "https://github.com/OCA/stock-logistics-transport", | ||
"depends": ["tms", "tms_product", "sale_management", "web"], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"wizard/sale_order_line_trip_views.xml", | ||
"wizard/seat_ticket_line_views.xml", | ||
"views/sale_order_views.xml", | ||
"views/tms_order_views.xml", | ||
"views/product_template_views.xml", | ||
], | ||
"assets": { | ||
"web.assets_backend": [ | ||
"tms_sale/static/src/js/line_trip_wizard_controller.js", | ||
"tms_sale/static/src/js/line_ticket_wizard_controller.js", | ||
"tms_sale/static/src/js/sale_order_line_product_field.js", | ||
], | ||
}, | ||
"license": "AGPL-3", | ||
"development_status": "Alpha", | ||
"maintainers": ["max3903", "santiagordz", "EdgarRetes"], | ||
"installable": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from . import sale_order_line | ||
from . import sale_order | ||
from . import seat_ticket | ||
from . import tms_order |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
# Copyright (C) 2024 Open Source Integrators | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
from markupsafe import Markup | ||
|
||
from odoo import _, api, fields, models | ||
|
||
|
||
class SaleOrder(models.Model): | ||
_inherit = "sale.order" | ||
|
||
tms_order_ids = fields.Many2many( | ||
"tms.order", | ||
compute="_compute_tms_order_ids", | ||
string="Transport orders associated to this sale", | ||
copy=False, | ||
) | ||
tms_order_count = fields.Integer( | ||
string="Transport Orders", compute="_compute_tms_order_ids" | ||
) | ||
|
||
has_tms_order = fields.Boolean(compute="_compute_has_tms_order") | ||
|
||
def action_view_trip_sale_order_line(self): | ||
return { | ||
"type": "ir.actions.act_window", | ||
"res_model": "sale.order.line.trip", | ||
"target": "new", | ||
"view_mode": "form", | ||
"view_type": "form", | ||
} | ||
|
||
@api.depends("order_line") | ||
def _compute_has_tms_order(self): | ||
for sale in self: | ||
has_tms_order = any( | ||
line.product_template_id.tms_trip | ||
and line.product_template_id.trip_product_type == "trip" | ||
for line in sale.order_line | ||
) | ||
sale.has_tms_order = has_tms_order | ||
|
||
@api.depends("order_line") | ||
def _compute_tms_order_ids(self): | ||
for sale in self: | ||
tms = self.env["tms.order"].search( | ||
[ | ||
"|", | ||
("sale_id", "=", sale.id), | ||
("sale_line_id", "in", sale.order_line.ids), | ||
] | ||
) | ||
sale.tms_order_ids = tms | ||
sale.tms_order_count = len(sale.tms_order_ids) | ||
|
||
def _tms_generate_line_tms_orders(self, new_tms_sol): | ||
""" | ||
Generate TMS Orders for the given sale order lines. | ||
Override this method to filter lines to generate TMS Orders for. | ||
""" | ||
self.ensure_one() | ||
new_tms_orders = self.env["tms.order"] | ||
|
||
for line in new_tms_sol: | ||
for i in range(int(line.product_uom_qty) - len(line.tms_order_ids)): | ||
vals = line._prepare_line_tms_values(line) | ||
tms_by_line = self.env["tms.order"].sudo().create(vals) | ||
line.write({"tms_order_ids": [(4, tms_by_line.id)]}) | ||
new_tms_orders |= tms_by_line | ||
i = i # pre-commit | ||
|
||
return new_tms_orders | ||
|
||
def _tms_generate(self): | ||
self.ensure_one() | ||
new_tms_orders = self.env["tms.order"] | ||
|
||
new_tms_line_sol = self.order_line.filtered( | ||
lambda L: L.product_id.trip_product_type == "trip" | ||
and len(L.tms_order_ids) != L.product_uom_qty | ||
and len(L.tms_order_ids) < L.product_uom_qty | ||
) | ||
|
||
new_tms_orders |= self._tms_generate_line_tms_orders(new_tms_line_sol) | ||
|
||
return new_tms_orders | ||
|
||
def _tms_generation(self): | ||
""" | ||
Create TMS Orders based on the products' configuration. | ||
:rtype: list(TMS Orders) | ||
:return: list of newly created TMS Orders | ||
""" | ||
created_tms_orders = self.env["tms.order"] | ||
|
||
for sale in self: | ||
new_tms_orders = self._tms_generate() | ||
|
||
if len(new_tms_orders) > 0: | ||
created_tms_orders |= new_tms_orders | ||
sale._post_tms_message(new_tms_orders) | ||
|
||
return created_tms_orders | ||
|
||
def _post_tms_message(self, tms_orders): | ||
""" | ||
Post messages to the Sale Order and the newly created TMS Orders | ||
""" | ||
self.ensure_one() | ||
for tms_order in tms_orders: | ||
tms_order.message_mail_with_source( | ||
"mail.message_origin_link", | ||
render_values={"self": tms_order, "origin": self}, | ||
subtype_id=self.env.ref("mail.mt_note").id, | ||
author_id=self.env.user.partner_id.id, | ||
) | ||
message = _( | ||
"Transport Order(s) Created: %s", | ||
Markup( | ||
f"""<a href=# data-oe-model=tms.order data-oe-id={tms_order.id}""" | ||
f""">{tms_order.name}</a>""" | ||
), | ||
) | ||
self.message_post(body=message) | ||
|
||
def _action_create_new_trips(self): | ||
if any( | ||
sol.product_id.trip_product_type == "trip" | ||
for sol in self.order_line.filtered( | ||
lambda x: x.display_type not in ("line_section", "line_note") | ||
) | ||
): | ||
self._tms_generation() | ||
|
||
def action_view_tms_order(self): | ||
tms_orders = self.mapped("tms_order_ids") | ||
action = self.env["ir.actions.act_window"]._for_xml_id( | ||
"tms.action_tms_dash_order" | ||
) | ||
if len(tms_orders) > 1: | ||
action["domain"] = [("id", "in", tms_orders.ids)] | ||
elif len(tms_orders) == 1: | ||
action["views"] = [(self.env.ref("tms.tms_order_view_form").id, "form")] | ||
action["res_id"] = tms_orders.id | ||
else: | ||
action = {"type": "ir.actions.act_window_close"} | ||
return action | ||
|
||
def remove_lines_with_trips( | ||
self, initial_trips, initial_line_ids, initial_quantities | ||
): | ||
current_order_line_ids = set(self.order_line.ids) | ||
removed_lines = initial_line_ids - current_order_line_ids | ||
|
||
if removed_lines: | ||
trips_to_delete = initial_trips.filtered( | ||
lambda trip_id: not (trip_id.sale_line_id & self.order_line) | ||
) | ||
if trips_to_delete: | ||
trips_to_delete.unlink() | ||
|
||
for line in self.order_line: | ||
if line.id in initial_quantities: | ||
if line.product_uom_qty < initial_quantities[line.id]: | ||
trips_to_delete = line.tms_order_ids[:1] | ||
if trips_to_delete: | ||
trips_to_delete.unlink() | ||
|
||
@api.model | ||
def create(self, vals): | ||
order = super().create(vals) | ||
if "order_line" in vals and order.has_tms_order: | ||
order._action_create_new_trips() | ||
return order | ||
|
||
@api.model | ||
def write(self, vals): | ||
initial_trips = self.env["tms.order"].search( | ||
[("sale_line_id", "in", self.order_line.ids)] | ||
) | ||
initial_order_line_ids = set(self.order_line.ids) | ||
initial_quantities = {line.id: line.product_uom_qty for line in self.order_line} | ||
|
||
result = super().write(vals) | ||
|
||
if "order_line" in vals and self.has_tms_order: | ||
self.remove_lines_with_trips( | ||
initial_trips, initial_order_line_ids, initial_quantities | ||
) | ||
self._action_create_new_trips() | ||
|
||
if "state" in vals: | ||
if self.state == "sale": | ||
stage = self.env.ref("tms.tms_stage_order_confirmed") | ||
elif self.state == "cancel": | ||
stage = self.env.ref("tms.tms_stage_order_cancelled") | ||
else: | ||
stage = self.env.ref("tms.tms_stage_order_draft") | ||
|
||
for line in self.order_line: | ||
for trip in line.tms_order_ids: | ||
trip.stage_id = stage | ||
|
||
return result | ||
Oops, something went wrong.