diff --git a/account_asset_stock_move/__init__.py b/account_asset_stock_move/__init__.py new file mode 100644 index 000000000000..feb76110de7b --- /dev/null +++ b/account_asset_stock_move/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2021 Ecosoft Co., Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import models diff --git a/account_asset_stock_move/__manifest__.py b/account_asset_stock_move/__manifest__.py new file mode 100644 index 000000000000..9a6d07c9f15b --- /dev/null +++ b/account_asset_stock_move/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2021 Ecosoft Co., Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Assets Management - Create asset during stock move", + "version": "14.0.1.0.0", + "license": "AGPL-3", + "depends": ["account_asset_management", "stock_account"], + "author": "Ecosoft, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/account-financial-tools", + "category": "Accounting & Finance", + "data": [ + "views/stock.xml", + ], + "development_status": "Alpha", + "maintainers": ["kittiu"], +} diff --git a/account_asset_stock_move/models/__init__.py b/account_asset_stock_move/models/__init__.py new file mode 100644 index 000000000000..e0c78acffb74 --- /dev/null +++ b/account_asset_stock_move/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2021 Ecosoft Co., Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import stock_move +from . import stock_picking diff --git a/account_asset_stock_move/models/stock_move.py b/account_asset_stock_move/models/stock_move.py new file mode 100644 index 000000000000..150a7a762c33 --- /dev/null +++ b/account_asset_stock_move/models/stock_move.py @@ -0,0 +1,90 @@ +# Copyright 2021 Ecosoft Co., Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _, models +from odoo.exceptions import UserError +from odoo.tests.common import Form + + +class StockMove(models.Model): + _inherit = "stock.move" + + def _generate_valuation_lines_data( + self, + partner_id, + qty, + debit_value, + credit_value, + debit_account_id, + credit_account_id, + description, + ): + """ + Assign Account's Asset Profile (if any) + """ + rslt = super()._generate_valuation_lines_data( + partner_id, + qty, + debit_value, + credit_value, + debit_account_id, + credit_account_id, + description, + ) + for entry in rslt.values(): + account = self.env["account.account"].browse(entry["account_id"]) + entry["asset_profile_id"] = account.asset_profile_id.id + return rslt + + def _create_account_move_line( + self, + credit_account_id, + debit_account_id, + journal_id, + qty, + description, + svl_id, + cost, + ): + """ + Create Asset (if asset_profile_id exists) + """ + res = super()._create_account_move_line( + credit_account_id, + debit_account_id, + journal_id, + qty, + description, + svl_id, + cost, + ) + for move in self.env["account.move"].search([("stock_move_id", "=", self.id)]): + for aml in move.line_ids.filtered("asset_profile_id"): + vals = move._prepare_asset_vals(aml) + if not aml.name: + raise UserError( + _("Asset name must be set in the label of the line.") + ) + asset_form = Form( + self.env["account.asset"] + .with_company(move.company_id) + .with_context(create_asset_from_move_line=True, move_id=move.id) + ) + for key, val in vals.items(): + setattr(asset_form, key, val) + asset = asset_form.save() + asset.analytic_tag_ids = aml.analytic_tag_ids + aml.with_context(allow_asset=True).asset_id = asset.id + refs = [ + "%s" + % tuple(name_get) + for name_get in move.line_ids.filtered( + "asset_profile_id" + ).asset_id.name_get() + ] + if refs: + message = _("This journal entry created the asset(s): %s") % ", ".join( + refs + ) + move.message_post(body=message) + return res diff --git a/account_asset_stock_move/models/stock_picking.py b/account_asset_stock_move/models/stock_picking.py new file mode 100644 index 000000000000..55c0aaf1f9fc --- /dev/null +++ b/account_asset_stock_move/models/stock_picking.py @@ -0,0 +1,40 @@ +# Copyright 2021 Ecosoft Co., Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + asset_count = fields.Integer(compute="_compute_asset_count") + + def _compute_asset_count(self): + for rec in self: + moves = self.env["account.move"].search( + [("stock_move_id", "in", rec.move_lines.ids)] + ) + rec.asset_count = sum(moves.mapped("asset_count")) + + def action_view_assets(self): + moves = self.env["account.move"].search( + [("stock_move_id", "in", self.move_lines.ids)] + ) + assets = ( + self.env["account.asset.line"] + .search([("move_id", "in", moves.ids)]) + .mapped("asset_id") + ) + action = self.env.ref("account_asset_management.account_asset_action") + action_dict = action.sudo().read()[0] + if len(assets) == 1: + res = self.env.ref( + "account_asset_management.account_asset_view_form", False + ) + action_dict["views"] = [(res and res.id or False, "form")] + action_dict["res_id"] = assets.id + elif assets: + action_dict["domain"] = [("id", "in", assets.ids)] + else: + action_dict = {"type": "ir.actions.act_window_close"} + return action_dict diff --git a/account_asset_stock_move/readme/CONFIGURE.rst b/account_asset_stock_move/readme/CONFIGURE.rst new file mode 100644 index 000000000000..c436eeeb918b --- /dev/null +++ b/account_asset_stock_move/readme/CONFIGURE.rst @@ -0,0 +1,6 @@ +For Product to create as asset (during stock move), setup on product category, + +* Inventory Valuation = Automated (realtime) +* Stock Valuation Account = Asset Profile's Asset Account + +With this setup, account move created during picking in will set asset profile, and result in asset creation. diff --git a/account_asset_stock_move/readme/CONTRIBUTORS.rst b/account_asset_stock_move/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..ab2279828dc8 --- /dev/null +++ b/account_asset_stock_move/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Ecosoft `_: + + * Kitti U. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import test_account_asset_stock_move diff --git a/account_asset_stock_move/tests/test_account_asset_stock_move.py b/account_asset_stock_move/tests/test_account_asset_stock_move.py new file mode 100644 index 000000000000..c407ab010c29 --- /dev/null +++ b/account_asset_stock_move/tests/test_account_asset_stock_move.py @@ -0,0 +1,77 @@ +# Copyright 2021 Ecosoft Co., Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests import common +from odoo.tests.common import Form + + +class TestAccountAssetStockMove(common.TransactionCase): + def setUp(self): + super(TestAccountAssetStockMove, self).setUp() + # Asset Profile + self.account_expense = self.env["account.account"].search( + [ + ( + "user_type_id", + "=", + self.env.ref("account.data_account_type_expenses").id, + ) + ], + limit=1, + ) + self.account_asset = self.env["account.account"].search( + [ + ( + "user_type_id", + "=", + self.env.ref("account.data_account_type_current_assets").id, + ) + ], + limit=1, + ) + self.journal_purchase = self.env["account.journal"].search( + [("type", "=", "purchase")], limit=1 + ) + self.asset_profile = self.env["account.asset.profile"].create( + { + "account_expense_depreciation_id": self.account_expense.id, + "account_asset_id": self.account_asset.id, + "account_depreciation_id": self.account_asset.id, + "journal_id": self.journal_purchase.id, + "name": "Furniture - 3 Years", + "method_time": "year", + "method_number": 3, + "method_period": "year", + } + ) + # Realtime valuation product + self.product_categ = self.env.ref("product.product_category_5") + self.product_categ.property_valuation = "real_time" + self.product_categ.property_stock_valuation_account_id = self.account_asset + self.product_desk = self.env.ref("product.product_product_4") + self.product_desk.categ_id = self.product_categ + self.picking_type_in = self.env.ref("stock.picking_type_in") + + def test_account_asset_stock_move(self): + """Create Picking In with realtime valuation product, + If account_asset_id in account move, asset profile will be set, + and asset will be created when stock move is done""" + with Form(self.env["stock.picking"]) as f: + f.picking_type_id = self.picking_type_in + with f.move_ids_without_package.new() as line: + line.product_id = self.product_desk + line.product_uom_qty = 1 + picking = f.save() + picking.action_confirm() + picking.move_lines[0].quantity_done = 1 + picking.button_validate() + self.assertEqual(picking.state, "done") + move = self.env["account.move"].search( + [("stock_move_id", "=", picking.move_lines[0].id)] + ) + move_line = move.line_ids.filtered(lambda l: l.debit) + self.assertEqual(move_line.account_id, self.account_asset) + self.assertEqual(picking.asset_count, 1) + res = picking.action_view_assets() + asset = self.env[res["res_model"]].browse(res["res_id"]) + self.assertEqual(asset.profile_id, self.asset_profile) diff --git a/account_asset_stock_move/views/stock.xml b/account_asset_stock_move/views/stock.xml new file mode 100644 index 000000000000..0d013802df7e --- /dev/null +++ b/account_asset_stock_move/views/stock.xml @@ -0,0 +1,28 @@ + + + + stock.picking.form + stock.picking + + + + + + + + + + diff --git a/setup/account_asset_stock_move/odoo/addons/account_asset_stock_move b/setup/account_asset_stock_move/odoo/addons/account_asset_stock_move new file mode 120000 index 000000000000..e8178e7422a5 --- /dev/null +++ b/setup/account_asset_stock_move/odoo/addons/account_asset_stock_move @@ -0,0 +1 @@ +../../../../account_asset_stock_move \ No newline at end of file diff --git a/setup/account_asset_stock_move/setup.py b/setup/account_asset_stock_move/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/account_asset_stock_move/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)