diff --git a/setup/stock_release_channel_shipment_advice_toursolver/odoo/addons/stock_release_channel_shipment_advice_toursolver b/setup/stock_release_channel_shipment_advice_toursolver/odoo/addons/stock_release_channel_shipment_advice_toursolver new file mode 120000 index 0000000000..24513c35d2 --- /dev/null +++ b/setup/stock_release_channel_shipment_advice_toursolver/odoo/addons/stock_release_channel_shipment_advice_toursolver @@ -0,0 +1 @@ +../../../../stock_release_channel_shipment_advice_toursolver \ No newline at end of file diff --git a/setup/stock_release_channel_shipment_advice_toursolver/setup.py b/setup/stock_release_channel_shipment_advice_toursolver/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/stock_release_channel_shipment_advice_toursolver/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_release_channel_shipment_advice_toursolver/README.rst b/stock_release_channel_shipment_advice_toursolver/README.rst new file mode 100644 index 0000000000..906c2edbbc --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/README.rst @@ -0,0 +1,74 @@ +================================================ +Stock Release Channel Shipment Advice Toursolver +================================================ + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fwms-lightgray.png?logo=github + :target: https://github.com/OCA/wms/tree/16.0/stock_release_channel_shipment_advice_toursolver + :alt: OCA/wms +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/wms-16-0/wms-16-0-stock_release_channel_shipment_advice_toursolver + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/wms&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Use TourSolver to plan shipment advices for ready and released pickings. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ACSONE SA/NV + +Contributors +~~~~~~~~~~~~ + +* Laurent Mignon +* Souheil Bejaoui + +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/wms `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_release_channel_shipment_advice_toursolver/__init__.py b/stock_release_channel_shipment_advice_toursolver/__init__.py new file mode 100644 index 0000000000..aee8895e7a --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/stock_release_channel_shipment_advice_toursolver/__manifest__.py b/stock_release_channel_shipment_advice_toursolver/__manifest__.py new file mode 100644 index 0000000000..5df250837a --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Stock Release Channel Shipment Advice Toursolver", + "summary": """ + Use TourSolver to plan shipment advices for ready and released pickings""", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/wms", + "depends": [ + "stock_release_channel_shipment_advice", + "shipment_advice_planner_toursolver", + ], + "data": ["views/toursolver_task.xml", "views/stock_release_channel.xml"], + "demo": [], +} diff --git a/stock_release_channel_shipment_advice_toursolver/models/__init__.py b/stock_release_channel_shipment_advice_toursolver/models/__init__.py new file mode 100644 index 0000000000..5943f65274 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/models/__init__.py @@ -0,0 +1,2 @@ +from . import stock_release_channel +from . import toursolver_task diff --git a/stock_release_channel_shipment_advice_toursolver/models/stock_release_channel.py b/stock_release_channel_shipment_advice_toursolver/models/stock_release_channel.py new file mode 100644 index 0000000000..59bfead281 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/models/stock_release_channel.py @@ -0,0 +1,25 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class StockReleaseChannel(models.Model): + + _inherit = "stock.release.channel" + + shipment_planning_method = fields.Selection( + selection_add=[("toursolver", "TourSolver")], + ondelete={"toursolver": "cascade"}, + ) + delivery_resource_ids = fields.Many2many( + comodel_name="toursolver.resource", + string="Delivery resources", + help="delivery resources to be considered in geo-optimazation", + ) + + def _get_new_planner(self): + self.ensure_one() + planner = super()._get_new_planner() + planner.delivery_resource_ids = self.delivery_resource_ids + return planner diff --git a/stock_release_channel_shipment_advice_toursolver/models/toursolver_task.py b/stock_release_channel_shipment_advice_toursolver/models/toursolver_task.py new file mode 100644 index 0000000000..97e7e9961f --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/models/toursolver_task.py @@ -0,0 +1,19 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ToursolverTask(models.Model): + + _inherit = "toursolver.task" + + release_channel_id = fields.Many2one( + comodel_name="stock.release.channel", string="Release Channel", readonly=True + ) + + def _get_new_shipment_advice_planer(self, resource, pickings_to_plan): + planner = super()._get_new_shipment_advice_planer(resource, pickings_to_plan) + planner.release_channel_id = self.release_channel_id + planner.picking_to_plan_ids = pickings_to_plan + return planner diff --git a/stock_release_channel_shipment_advice_toursolver/readme/CONTRIBUTORS.rst b/stock_release_channel_shipment_advice_toursolver/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..7bbe49c97f --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Laurent Mignon +* Souheil Bejaoui diff --git a/stock_release_channel_shipment_advice_toursolver/readme/DESCRIPTION.rst b/stock_release_channel_shipment_advice_toursolver/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..17f4dc0ed5 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Use TourSolver to plan shipment advices for ready and released pickings. diff --git a/stock_release_channel_shipment_advice_toursolver/static/description/icon.png b/stock_release_channel_shipment_advice_toursolver/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/stock_release_channel_shipment_advice_toursolver/static/description/icon.png differ diff --git a/stock_release_channel_shipment_advice_toursolver/static/description/index.html b/stock_release_channel_shipment_advice_toursolver/static/description/index.html new file mode 100644 index 0000000000..c94bf91fd2 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/static/description/index.html @@ -0,0 +1,420 @@ + + + + + + +Stock Release Channel Shipment Advice Toursolver + + + +
+

Stock Release Channel Shipment Advice Toursolver

+ + +

Beta License: AGPL-3 OCA/wms Translate me on Weblate Try me on Runboat

+

Use TourSolver to plan shipment advices for ready and released pickings.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub 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.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • ACSONE SA/NV
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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/wms project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/stock_release_channel_shipment_advice_toursolver/tests/__init__.py b/stock_release_channel_shipment_advice_toursolver/tests/__init__.py new file mode 100644 index 0000000000..232d2f6b4e --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/tests/__init__.py @@ -0,0 +1 @@ +from . import test_shipment_advice_planner_toursolver diff --git a/stock_release_channel_shipment_advice_toursolver/tests/cassettes/TestShipmentAdvicePlannerToursolver.test_plan_shipment_toursolver.yaml b/stock_release_channel_shipment_advice_toursolver/tests/cassettes/TestShipmentAdvicePlannerToursolver.test_plan_shipment_toursolver.yaml new file mode 100644 index 0000000000..ce3e7f6be0 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/tests/cassettes/TestShipmentAdvicePlannerToursolver.test_plan_shipment_toursolver.yaml @@ -0,0 +1,175 @@ +interactions: +- request: + body: '{"simulationName": "TST/00000014", "countryCode": "US", "beginDate": "2023-02-22", + "language": "en_US", "depots": [{"x": 0.0, "y": 0.0, "id": "dep_1"}], "orders": + [{"customerId": false, "fixedVisitDuration": "00:03:00", "id": 9, "label": "Wood + Corner", "phone": "(623)-853-7197", "type": 0, "x": 0.0, "y": 0.0, "customDataMap": + {"address": "Wood Corner\n1839 Arbor Way\n\nTurlock CA 95380\nUnited States"}, + "timeWindows": [{"beginTime": "08:00", "endTime": "17:00"}]}, {"customerId": + false, "fixedVisitDuration": "00:03:00", "id": 31, "label": "Gemini Furniture, + Oscar Morgan", "phone": "(561)-239-1744", "type": 0, "x": 0.0, "y": 0.0, "customDataMap": + {"address": "Gemini Furniture\n317 Fairchild Dr\n\nFairfield CA 94535\nUnited + States"}, "timeWindows": [{"beginTime": "08:00", "endTime": "17:00"}]}], "resources": + [{"travelPenalty": 0.0, "workPenalty": 0.0, "workStartTime": "12:40:00", "fixedLoadingDuration": + "00:00:00", "id": "D1", "mobileLogin": "d1@email.com", "openStart": false, "loadBeforeDeparture": + true, "noReload": true, "globalCapacity": 9999, "useAllCapacities": false, "startX": + 0.0, "startY": 0.0, "endX": 0.0, "endY": 0.0}, {"travelPenalty": 0.0, "workPenalty": + 0.0, "workStartTime": "12:40:00", "fixedLoadingDuration": "00:00:00", "id": + "D2", "mobileLogin": "d2@email.com", "openStart": false, "loadBeforeDeparture": + true, "noReload": true, "globalCapacity": 9999, "useAllCapacities": false, "startX": + 0.0, "startY": 0.0, "endX": 0.0, "endY": 0.0}], "options": {"maxOptimDuration": + "00:00:00", "vehicleCode": "deliveryIntermediateVehicle", "useForbiddenTransitAreas": + false}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1596' + Content-Type: + - application/json + User-Agent: + - python-requests/2.28.2 + method: POST + uri: https://geoservices.geoconcept.com/ToursolverCloud/api/ts/toursolver/optimize?tsCloudApiKey=fake_api_key + response: + body: + string: '{"message":null,"status":"OK","taskId":"7FFFFE798712E6718ezjI-ehRJaG_Tl68JRX_w"}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - Accept,Upgrade-Insecure-Requests,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization + Access-Control-Allow-Methods: + - PUT, GET, POST, DELETE, PATCH, OPTIONS + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - '*,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' + Access-Control-Max-Age: + - '1728000' + Connection: + - keep-alive + Content-Type: + - application/json;charset=UTF-8 + Date: + - Wed, 22 Feb 2023 11:40:50 GMT + Set-Cookie: + - INGRESSTSPRODCOOKIE=1677066049.544.989.142109|526296c4243d90e279c23661c06665b2; + Path=/ToursolverCloud; Secure; HttpOnly; SameSite=None + - JSESSIONID=2044873206CFDEC19214C8F337E64D40; Path=/ToursolverCloud; HttpOnly; + SameSite=None; Secure + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Transfer-Encoding: + - chunked + vary: + - origin + status: + code: 200 + message: '' +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.28.2 + method: GET + uri: https://geoservices.geoconcept.com/ToursolverCloud/api/ts/toursolver/status?taskId=7FFFFE798712E6718ezjI-ehRJaG_Tl68JRX_w&tsCloudApiKey=fake_api_key + response: + body: + string: '{"message":null,"status":"OK","optimizeStatus":"TERMINATED","startTime":1677066049923,"initialCost":1,"currentCost":1,"initialDriveDistance":0,"currentDriveDistance":0,"initialDriveTime":0,"currentDriveTime":0,"initialDriveCost":0,"currentDriveCost":0,"initialWorkTime":360,"currentWorkTime":360,"initialWorkCost":1,"currentWorkCost":1,"initialOverWorkTime":0,"currentOverWorkTime":0,"initialOverWorkCost":0,"currentOverWorkCost":0,"initialRestTime":0,"currentRestTime":0,"initialNightsCost":0,"currentNightsCost":0,"initialCourierCost":0,"currentCourierCost":0,"initialDeliveryCost":0,"currentDeliveryCost":0,"initialFixedCost":0,"currentFixedCost":0,"initialPickUpQuantity":0.0,"currentPickUpQuantity":0.0,"initialDeliveredQuantity":0.0,"currentDeliveredQuantity":0.0,"initialUnplannedVisits":0,"currentUnplannedVisits":0,"initialPlannedVisits":0,"currentPlannedVisits":0,"currentVisitsNb":2,"initialLateTime":0,"currentLateTime":0,"initialWaitTime":0,"currentWaitTime":0,"mileageChartRemainingTime":0,"initialCo2":0.0,"currentCo2":0.0,"initialOpenTourNumber":1,"currentOpenTourNumber":1,"subOptimNb":0,"subOptimWaitingNb":0,"subOptimRunningNb":0,"subOptimFinishedNb":0,"subOptimErrorNb":0,"subOptimAbortedNb":0,"simulationId":"7FFFFE798712E6BBmz4AfuOzSfG-VSMVoay9Qg","positionInQueue":0}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - Accept,Upgrade-Insecure-Requests,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization + Access-Control-Allow-Methods: + - PUT, GET, POST, DELETE, PATCH, OPTIONS + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - '*,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' + Access-Control-Max-Age: + - '1728000' + Connection: + - keep-alive + Content-Type: + - application/json;charset=UTF-8 + Date: + - Wed, 22 Feb 2023 11:41:35 GMT + Set-Cookie: + - INGRESSTSPRODCOOKIE=1677066096.688.989.843512|526296c4243d90e279c23661c06665b2; + Path=/ToursolverCloud; Secure; HttpOnly; SameSite=None + - JSESSIONID=E3F87122918D8E6CA7AFC7AB344594C2; Path=/ToursolverCloud; HttpOnly; + SameSite=None; Secure + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Transfer-Encoding: + - chunked + vary: + - origin + status: + code: 200 + message: '' +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.28.2 + method: GET + uri: https://geoservices.geoconcept.com/ToursolverCloud/api/ts/toursolver/result?taskId=7FFFFE798712E6718ezjI-ehRJaG_Tl68JRX_w&tsCloudApiKey=fake_api_key + response: + body: + string: '{"message":null,"status":"OK","plannedOrders":[{"resourceId":"D2","dayId":"1","stopId":"Start","stopPosition":0,"stopY":0.0,"stopX":0.0,"stopType":1,"stopDriveTime":"00:00","stopStartTime":"12:40","stopDuration":"00:00","stopStatus":0,"stopDriveDistance":0,"stopElapsedDistance":0,"placeName":null,"placeAddress":null,"aggregationInfo":null,"walkGoupRootId":null,"stopDriveSpeed":0.0},{"resourceId":"D2","dayId":"1","stopId":"Reload + (dep_1)","stopPosition":0,"stopY":0.0,"stopX":0.0,"stopType":4,"stopDriveTime":"00:00","stopStartTime":"12:40","stopDuration":"00:00","stopStatus":0,"stopDriveDistance":0,"stopElapsedDistance":0,"placeName":null,"placeAddress":null,"aggregationInfo":null,"walkGoupRootId":null,"stopDriveSpeed":0.0},{"resourceId":"D2","dayId":"1","stopId":"31","stopPosition":1,"stopY":0.0,"stopX":0.0,"stopType":0,"stopDriveTime":"00:00","stopStartTime":"12:40","stopDuration":"00:03","stopStatus":0,"stopDriveDistance":0,"stopElapsedDistance":0,"placeName":null,"placeAddress":null,"aggregationInfo":null,"walkGoupRootId":null,"stopDriveSpeed":0.0},{"resourceId":"D2","dayId":"1","stopId":"9","stopPosition":2,"stopY":0.0,"stopX":0.0,"stopType":0,"stopDriveTime":"00:00","stopStartTime":"12:43","stopDuration":"00:03","stopStatus":0,"stopDriveDistance":0,"stopElapsedDistance":0,"placeName":null,"placeAddress":null,"aggregationInfo":null,"walkGoupRootId":null,"stopDriveSpeed":0.0},{"resourceId":"D2","dayId":"1","stopId":"End","stopPosition":0,"stopY":0.0,"stopX":0.0,"stopType":2,"stopDriveTime":"00:00","stopStartTime":"12:46","stopDuration":"00:00","stopStatus":0,"stopDriveDistance":0,"stopElapsedDistance":0,"placeName":null,"placeAddress":null,"aggregationInfo":null,"walkGoupRootId":null,"stopDriveSpeed":0.0}],"unplannedOrders":[],"warnings":[{"objectType":"R","id":"D1","constraint":29,"constraintName":"WORKPENALTY","value":"0.0","message":"Journey + cost and hourly cost can not be set both to zero: default values will be applied.","messageId":6,"i18nMessageCode":"missingMandatoryPenalties"},{"objectType":"R","id":"D2","constraint":29,"constraintName":"WORKPENALTY","value":"0.0","message":"Journey + cost and hourly cost can not be set both to zero: default values will be applied.","messageId":6,"i18nMessageCode":"missingMandatoryPenalties"}],"taskId":"7FFFFE798712E6718ezjI-ehRJaG_Tl68JRX_w","simulationId":"7FFFFE798712E6BBmz4AfuOzSfG-VSMVoay9Qg","inputData":null}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - Accept,Upgrade-Insecure-Requests,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization + Access-Control-Allow-Methods: + - PUT, GET, POST, DELETE, PATCH, OPTIONS + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - '*,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' + Access-Control-Max-Age: + - '1728000' + Connection: + - keep-alive + Content-Type: + - application/json;charset=UTF-8 + Date: + - Wed, 22 Feb 2023 11:41:36 GMT + Set-Cookie: + - INGRESSTSPRODCOOKIE=1677066097.096.987.98129|526296c4243d90e279c23661c06665b2; + Path=/ToursolverCloud; Secure; HttpOnly; SameSite=None + - JSESSIONID=0C98B9F5A5471A9D457F56A4370F6E1C; Path=/ToursolverCloud; HttpOnly; + SameSite=None; Secure + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + Transfer-Encoding: + - chunked + vary: + - origin + status: + code: 200 + message: '' +version: 1 diff --git a/stock_release_channel_shipment_advice_toursolver/tests/test_shipment_advice_planner_toursolver.py b/stock_release_channel_shipment_advice_toursolver/tests/test_shipment_advice_planner_toursolver.py new file mode 100644 index 0000000000..c6effc6d43 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/tests/test_shipment_advice_planner_toursolver.py @@ -0,0 +1,47 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from vcr_unittest import VCRTestCase + +from odoo.addons.stock_release_channel.tests.common import ChannelReleaseCase + + +class TestShipmentAdvicePlannerToursolver(VCRTestCase, ChannelReleaseCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.resource_1 = cls.env.ref( + "shipment_advice_planner_toursolver.toursolver_resource_r1_demo" + ) + cls.resource_2 = cls.env.ref( + "shipment_advice_planner_toursolver.toursolver_resource_r2_demo" + ) + + (cls.picking + cls.picking2 + cls.picking3).unlink() + cls.pickings = cls.env["stock.picking"].search( + [("picking_type_code", "=", "outgoing"), ("partner_id", "!=", False)] + ) + cls.channel.picking_ids = cls.pickings + cls.pickings.move_ids.write({"procure_method": "make_to_stock"}) + cls.pickings.action_assign() + cls.channel.shipment_planning_method = "toursolver" + cls.channel.delivery_resource_ids = cls.resource_1 | cls.resource_2 + + def test_plan_shipment_toursolver(self): + pickings = self.channel.picking_to_plan_ids + self.channel.button_plan_shipments() + self.assertFalse(self.channel.shipment_advice_ids) + self.assertEqual(len(pickings.toursolver_task_id), 1) + task = pickings.toursolver_task_id + task.button_send_request() + self.assertEqual(task.state, "in_progress") + self.assertFalse(task.toursolver_error_message) + task.button_check_status() + self.assertEqual(task.state, "success") + task.button_get_result() + self.assertEqual(task.state, "done") + self.assertEqual( + task.shipment_advice_ids.toursolver_resource_id, self.resource_2 + ) + self.assertTrue(self.channel.shipment_advice_ids) + self.assertEqual(self.channel.shipment_advice_ids, task.shipment_advice_ids) diff --git a/stock_release_channel_shipment_advice_toursolver/views/stock_release_channel.xml b/stock_release_channel_shipment_advice_toursolver/views/stock_release_channel.xml new file mode 100644 index 0000000000..7d37508235 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/views/stock_release_channel.xml @@ -0,0 +1,27 @@ + + + + + + stock.release.channel + + + + + + + + + + + + + diff --git a/stock_release_channel_shipment_advice_toursolver/views/toursolver_task.xml b/stock_release_channel_shipment_advice_toursolver/views/toursolver_task.xml new file mode 100644 index 0000000000..df3fd45b33 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/views/toursolver_task.xml @@ -0,0 +1,21 @@ + + + + + + toursolver.task + + + + + + + + + + + diff --git a/stock_release_channel_shipment_advice_toursolver/wizards/__init__.py b/stock_release_channel_shipment_advice_toursolver/wizards/__init__.py new file mode 100644 index 0000000000..f1f4bd57b3 --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/wizards/__init__.py @@ -0,0 +1 @@ +from . import shipment_advice_planner diff --git a/stock_release_channel_shipment_advice_toursolver/wizards/shipment_advice_planner.py b/stock_release_channel_shipment_advice_toursolver/wizards/shipment_advice_planner.py new file mode 100644 index 0000000000..7951473f2d --- /dev/null +++ b/stock_release_channel_shipment_advice_toursolver/wizards/shipment_advice_planner.py @@ -0,0 +1,14 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class ShipmentAdvicePlanner(models.TransientModel): + + _inherit = "shipment.advice.planner" + + def _prepare_toursolver_task_vals(self, warehouse, pickings_to_plan): + vals = super()._prepare_toursolver_task_vals(warehouse, pickings_to_plan) + vals.update({"release_channel_id": self.release_channel_id.id}) + return vals