feat: Implement asset transfer functionality with a new transfer log, in_transit status for assets, and make depreciation fields readonly.
This commit is contained in:
parent
e60e85c30f
commit
5ec64ef131
@ -11,7 +11,7 @@
|
|||||||
- Asset Transfer Wizard
|
- Asset Transfer Wizard
|
||||||
""",
|
""",
|
||||||
'author': 'Antigravity',
|
'author': 'Antigravity',
|
||||||
'depends': ['base', 'account_asset', 'asset_code_field', 'product', 'stock', 'purchase'],
|
'depends': ['base', 'account_asset', 'asset_code_field', 'product', 'stock', 'purchase', 'hr'],
|
||||||
'data': [
|
'data': [
|
||||||
'security/ga_asset_security.xml',
|
'security/ga_asset_security.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
@ -19,6 +19,7 @@
|
|||||||
'views/account_asset_views.xml',
|
'views/account_asset_views.xml',
|
||||||
'views/stock_picking_views.xml',
|
'views/stock_picking_views.xml',
|
||||||
'views/product_template_views.xml',
|
'views/product_template_views.xml',
|
||||||
|
'views/asset_transfer_log_views.xml',
|
||||||
'wizard/asset_transfer_views.xml',
|
'wizard/asset_transfer_views.xml',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
|
|||||||
@ -3,3 +3,4 @@ from . import stock_move
|
|||||||
from . import stock_picking
|
from . import stock_picking
|
||||||
from . import account_move
|
from . import account_move
|
||||||
from . import product_template
|
from . import product_template
|
||||||
|
from . import ga_asset_transfer_log
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -7,6 +7,10 @@ class AccountAsset(models.Model):
|
|||||||
product_id = fields.Many2one('product.product', string='Product')
|
product_id = fields.Many2one('product.product', string='Product')
|
||||||
description = fields.Text(string='Description')
|
description = fields.Text(string='Description')
|
||||||
|
|
||||||
|
location_id = fields.Many2one('stock.location', string='Location', domain="[('company_id', '=', company_id)]")
|
||||||
|
employee_id = fields.Many2one('hr.employee', string='Employee', domain="[('company_id', '=', company_id)]")
|
||||||
|
in_transit = fields.Boolean(string='In Transit', default=False, help="Asset is currently being transferred between companies.")
|
||||||
|
|
||||||
@api.model_create_multi
|
@api.model_create_multi
|
||||||
def create(self, vals_list):
|
def create(self, vals_list):
|
||||||
for vals in vals_list:
|
for vals in vals_list:
|
||||||
@ -45,6 +49,34 @@ class AccountAsset(models.Model):
|
|||||||
|
|
||||||
vals['asset_code'] = f"{prefix}/{year}{sequence}"
|
vals['asset_code'] = f"{prefix}/{year}{sequence}"
|
||||||
|
|
||||||
|
# Remove original_value if it is 0.0 to allow computation from lines later
|
||||||
|
if 'original_value' in vals and vals['original_value'] == 0.0:
|
||||||
|
del vals['original_value']
|
||||||
|
|
||||||
|
# Populate accounting fields from Asset Model if not already set
|
||||||
|
if vals.get('model_id'):
|
||||||
|
model = self.env['account.asset'].browse(vals['model_id'])
|
||||||
|
if model:
|
||||||
|
if not vals.get('method'):
|
||||||
|
vals['method'] = model.method
|
||||||
|
if not vals.get('method_number'):
|
||||||
|
vals['method_number'] = model.method_number
|
||||||
|
if not vals.get('method_period'):
|
||||||
|
vals['method_period'] = model.method_period
|
||||||
|
if not vals.get('prorata_computation_type'):
|
||||||
|
vals['prorata_computation_type'] = model.prorata_computation_type
|
||||||
|
|
||||||
|
if not vals.get('account_asset_id'):
|
||||||
|
vals['account_asset_id'] = model.account_asset_id.id
|
||||||
|
if not vals.get('account_depreciation_id'):
|
||||||
|
vals['account_depreciation_id'] = model.account_depreciation_id.id
|
||||||
|
if not vals.get('account_depreciation_expense_id'):
|
||||||
|
vals['account_depreciation_expense_id'] = model.account_depreciation_expense_id.id
|
||||||
|
if not vals.get('journal_id'):
|
||||||
|
vals['journal_id'] = model.journal_id.id
|
||||||
|
if not vals.get('analytic_distribution') and model.analytic_distribution:
|
||||||
|
vals['analytic_distribution'] = model.analytic_distribution
|
||||||
|
|
||||||
return super(AccountAsset, self).create(vals_list)
|
return super(AccountAsset, self).create(vals_list)
|
||||||
|
|
||||||
def action_open_transfer_wizard(self):
|
def action_open_transfer_wizard(self):
|
||||||
|
|||||||
119
models/ga_asset_transfer_log.py
Normal file
119
models/ga_asset_transfer_log.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
class GaAssetTransferLog(models.Model):
|
||||||
|
_name = 'ga.asset.transfer.log'
|
||||||
|
_description = 'Asset Transfer Log'
|
||||||
|
_order = 'create_date desc'
|
||||||
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||||
|
|
||||||
|
name = fields.Char(string='Transfer Reference', required=True, copy=False, readonly=True, default=lambda self: _('New'))
|
||||||
|
asset_id = fields.Many2one('account.asset', string='Asset', required=True, readonly=True, help="Asset being transferred.")
|
||||||
|
source_company_id = fields.Many2one('res.company', string='Source Company', required=True, readonly=True)
|
||||||
|
target_company_id = fields.Many2one('res.company', string='Target Company', required=True, readonly=True)
|
||||||
|
user_id = fields.Many2one('res.users', string='Requested By', required=True, readonly=True, default=lambda self: self.env.user)
|
||||||
|
transfer_date = fields.Date(string='Request Date', default=fields.Date.context_today, readonly=True)
|
||||||
|
|
||||||
|
note = fields.Text(string='Transfer Note', readonly=True)
|
||||||
|
|
||||||
|
state = fields.Selection([
|
||||||
|
('draft', 'Draft'),
|
||||||
|
('transit', 'In Transit'),
|
||||||
|
('done', 'Done'),
|
||||||
|
('cancel', 'Cancelled')
|
||||||
|
], string='Status', default='draft', tracking=True, copy=False)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def create(self, vals):
|
||||||
|
if vals.get('name', _('New')) == _('New'):
|
||||||
|
vals['name'] = self.env['ir.sequence'].next_by_code('ga.asset.transfer.log') or _('New')
|
||||||
|
return super(GaAssetTransferLog, self).create(vals)
|
||||||
|
|
||||||
|
def action_validate(self):
|
||||||
|
self.ensure_one()
|
||||||
|
if self.state != 'transit':
|
||||||
|
raise UserError(_("You can only validate transfers that are currently In Transit."))
|
||||||
|
|
||||||
|
# Check if user is allowed to validate (must be in target company or have access)
|
||||||
|
# Assuming if they can see the button and access the record rules allow it, but let's double check company context
|
||||||
|
if self.env.company != self.target_company_id:
|
||||||
|
raise UserError(_("You must be logged into the Target Company (%s) to validate this transfer.", self.target_company_id.name))
|
||||||
|
|
||||||
|
# Perform the logic that was previously in the wizard
|
||||||
|
old_asset = self.asset_id
|
||||||
|
target_company = self.target_company_id
|
||||||
|
|
||||||
|
# Logic adapted from original wizard
|
||||||
|
if old_asset.state in ('draft', 'model'):
|
||||||
|
old_asset.sudo().write({'company_id': target_company.id})
|
||||||
|
old_asset.sudo().message_post(body=f"Asset transfer validated by {self.env.user.name}. Received in {target_company.name}.")
|
||||||
|
else:
|
||||||
|
# Running Asset -> Close and Clone
|
||||||
|
vals = {
|
||||||
|
'name': old_asset.name,
|
||||||
|
'product_id': old_asset.product_id.id,
|
||||||
|
'asset_code': old_asset.asset_code,
|
||||||
|
'original_value': old_asset.original_value,
|
||||||
|
'already_depreciated_amount_import': old_asset.original_value - old_asset.value_residual,
|
||||||
|
'acquisition_date': old_asset.acquisition_date,
|
||||||
|
'prorata_date': old_asset.prorata_date,
|
||||||
|
'method': old_asset.method,
|
||||||
|
'method_number': old_asset.method_number,
|
||||||
|
'method_period': old_asset.method_period,
|
||||||
|
'method_progress_factor': old_asset.method_progress_factor,
|
||||||
|
'prorata_computation_type': old_asset.prorata_computation_type,
|
||||||
|
'company_id': target_company.id,
|
||||||
|
'location_id': old_asset.location_id.id, # Copy location? Maybe not if it's new company. But user surely wants to update it later.
|
||||||
|
'employee_id': old_asset.employee_id.id, # Keep employee if moving with them?
|
||||||
|
'state': 'draft',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find Asset Model in Target Company
|
||||||
|
if old_asset.product_id:
|
||||||
|
product = old_asset.product_id.with_company(target_company)
|
||||||
|
account = product.property_account_expense_id or product.categ_id.property_account_expense_categ_id
|
||||||
|
|
||||||
|
if account and account.asset_model:
|
||||||
|
model = account.asset_model
|
||||||
|
vals['model_id'] = model.id
|
||||||
|
vals['account_asset_id'] = model.account_asset_id.id
|
||||||
|
vals['account_depreciation_id'] = model.account_depreciation_id.id
|
||||||
|
vals['account_depreciation_expense_id'] = model.account_depreciation_expense_id.id
|
||||||
|
vals['journal_id'] = model.journal_id.id
|
||||||
|
|
||||||
|
# Close Old Asset
|
||||||
|
old_asset.depreciation_move_ids.filtered(lambda m: m.state == 'draft').with_context(force_delete=True).sudo().unlink()
|
||||||
|
old_asset.sudo().write({
|
||||||
|
'state': 'close',
|
||||||
|
'active': False,
|
||||||
|
'in_transit': False # No longer in transit
|
||||||
|
})
|
||||||
|
old_asset.sudo().message_post(body=f"Asset transfer validated. Closed and moved to {target_company.name}.")
|
||||||
|
|
||||||
|
# Create New Asset
|
||||||
|
new_asset = self.env['account.asset'].sudo().create(vals)
|
||||||
|
new_asset.sudo().message_post(body=f"Asset received from {self.source_company_id.name}. Transfer Ref: {self.name}")
|
||||||
|
|
||||||
|
self.write({'state': 'done'})
|
||||||
|
|
||||||
|
# Unlock old asset just in case (if it was simple move)
|
||||||
|
if old_asset.id: # If simple move, old_asset is still the active one
|
||||||
|
old_asset.sudo().write({'in_transit': False})
|
||||||
|
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'params': {
|
||||||
|
'title': _('Success'),
|
||||||
|
'message': _('Asset has been successfully transferred.'),
|
||||||
|
'sticky': False,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def action_cancel(self):
|
||||||
|
self.ensure_one()
|
||||||
|
if self.state == 'done':
|
||||||
|
raise UserError(_("You cannot cancel a completed transfer."))
|
||||||
|
|
||||||
|
self.asset_id.sudo().write({'in_transit': False})
|
||||||
|
self.write({'state': 'cancel'})
|
||||||
@ -20,4 +20,10 @@
|
|||||||
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
|
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="rule_ga_asset_transfer_log_multi_company" model="ir.rule">
|
||||||
|
<field name="name">Asset Transfer Log Multi Company</field>
|
||||||
|
<field name="model_id" ref="model_ga_asset_transfer_log"/>
|
||||||
|
<field name="domain_force">['|', ('source_company_id', 'in', company_ids), ('target_company_id', 'in', company_ids)]</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_ga_asset_transfer_wizard_user,ga.asset.transfer.wizard.user,model_ga_asset_transfer_wizard,group_ga_asset_user,1,1,1,0
|
access_ga_asset_transfer_wizard_user,ga.asset.transfer.wizard.user,model_ga_asset_transfer_wizard,group_ga_asset_user,1,1,1,0
|
||||||
access_ga_asset_transfer_wizard_manager,ga.asset.transfer.wizard.manager,model_ga_asset_transfer_wizard,group_ga_asset_manager,1,1,1,1
|
access_ga_asset_transfer_wizard_manager,ga.asset.transfer.wizard.manager,model_ga_asset_transfer_wizard,group_ga_asset_manager,1,1,1,1
|
||||||
|
access_ga_asset_transfer_log_user,ga.asset.transfer.log.user,model_ga_asset_transfer_log,group_ga_asset_user,1,1,1,0
|
||||||
|
access_ga_asset_transfer_log_manager,ga.asset.transfer.log.manager,model_ga_asset_transfer_log,group_ga_asset_manager,1,1,1,1
|
||||||
|
|||||||
|
@ -26,7 +26,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Fixed Asset">
|
<form string="Fixed Asset">
|
||||||
<header>
|
<header>
|
||||||
<button name="action_open_transfer_wizard" string="Transfer Asset" type="object" class="oe_highlight" invisible="state == 'model'"/>
|
<button name="action_open_transfer_wizard" string="Transfer Asset" type="object" class="oe_highlight" invisible="state == 'model' or in_transit"/>
|
||||||
<field name="state" widget="statusbar" statusbar_visible="draft,open,close"/>
|
<field name="state" widget="statusbar" statusbar_visible="draft,open,close"/>
|
||||||
</header>
|
</header>
|
||||||
<sheet>
|
<sheet>
|
||||||
@ -47,8 +47,23 @@
|
|||||||
<field name="original_value"/>
|
<field name="original_value"/>
|
||||||
<field name="model_id" string="Asset Model"/>
|
<field name="model_id" string="Asset Model"/>
|
||||||
<field name="company_id" groups="base.group_multi_company" readonly="1"/>
|
<field name="company_id" groups="base.group_multi_company" readonly="1"/>
|
||||||
|
<field name="location_id"/>
|
||||||
|
<field name="employee_id"/>
|
||||||
|
<field name="employee_id"/>
|
||||||
|
<field name="in_transit" invisible="1"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
<group string="Depreciation Board">
|
||||||
|
<label for="method_number" string="Duration"/>
|
||||||
|
<div class="o_row">
|
||||||
|
<field name="method_number" nolabel="1" readonly="1" force_save="1"/>
|
||||||
|
<field name="method_period" nolabel="1" readonly="1" force_save="1"/>
|
||||||
|
</div>
|
||||||
|
<!-- Hidden fields for logic -->
|
||||||
|
<field name="method" invisible="1"/>
|
||||||
|
<field name="prorata_computation_type" invisible="1"/>
|
||||||
|
</group>
|
||||||
|
<!-- Accounting Group Removed as per request -->
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="Description">
|
<page string="Description">
|
||||||
<field name="description"/>
|
<field name="description"/>
|
||||||
@ -67,25 +82,15 @@
|
|||||||
<field name="name">Assets</field>
|
<field name="name">Assets</field>
|
||||||
<field name="res_model">account.asset</field>
|
<field name="res_model">account.asset</field>
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="view_id" ref="view_ga_account_asset_tree"/>
|
<field name="view_ids" eval="[(5, 0, 0),
|
||||||
|
(0, 0, {'view_mode': 'tree', 'view_id': ref('view_ga_account_asset_tree')}),
|
||||||
|
(0, 0, {'view_mode': 'form', 'view_id': ref('view_ga_account_asset_form')})]"/>
|
||||||
<field name="search_view_id" ref="account_asset.view_account_asset_search"/>
|
<field name="search_view_id" ref="account_asset.view_account_asset_search"/>
|
||||||
<field name="domain">[('state', '!=', 'model')]</field> <!-- Filter out Asset Models -->
|
<field name="domain">[('state', '!=', 'model')]</field> <!-- Filter out Asset Models -->
|
||||||
<field name="context">{'default_state': 'draft'}</field>
|
<field name="context">{'default_state': 'draft'}</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="action_ga_asset_tree_view_link" model="ir.actions.act_window.view">
|
<!-- Duplicate view links removed -->
|
||||||
<field name="sequence" eval="1"/>
|
|
||||||
<field name="view_mode">tree</field>
|
|
||||||
<field name="view_id" ref="view_ga_account_asset_tree"/>
|
|
||||||
<field name="act_window_id" ref="action_ga_asset_management"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="action_ga_asset_form_view_link" model="ir.actions.act_window.view">
|
|
||||||
<field name="sequence" eval="2"/>
|
|
||||||
<field name="view_mode">form</field>
|
|
||||||
<field name="view_id" ref="view_ga_account_asset_form"/>
|
|
||||||
<field name="act_window_id" ref="action_ga_asset_management"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Menu Items -->
|
<!-- Menu Items -->
|
||||||
<menuitem id="menu_ga_root" name="General Affair" web_icon="ga_asset_management,static/description/icon.png" sequence="10" groups="ga_asset_management.group_ga_asset_user"/>
|
<menuitem id="menu_ga_root" name="General Affair" web_icon="ga_asset_management,static/description/icon.png" sequence="10" groups="ga_asset_management.group_ga_asset_user"/>
|
||||||
@ -96,4 +101,49 @@
|
|||||||
action="action_ga_asset_management"
|
action="action_ga_asset_management"
|
||||||
sequence="1"/>
|
sequence="1"/>
|
||||||
|
|
||||||
|
<!-- Inheritance to modify Standard Account Asset Form -->
|
||||||
|
<record id="view_account_asset_form_inherit_ga" model="ir.ui.view">
|
||||||
|
<field name="name">account.asset.form.inherit.ga</field>
|
||||||
|
<field name="model">account.asset</field>
|
||||||
|
<field name="inherit_id" ref="account_asset.view_account_asset_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='method']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='method_number']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='method_period']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='prorata_computation_type']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='account_asset_id']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='account_depreciation_id']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='account_depreciation_expense_id']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='journal_id']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//page[@name='main_page']//field[@name='analytic_distribution']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
<attribute name="force_save">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
83
views/asset_transfer_log_views.xml
Normal file
83
views/asset_transfer_log_views.xml
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_ga_asset_transfer_log_tree" model="ir.ui.view">
|
||||||
|
<field name="name">ga.asset.transfer.log.tree</field>
|
||||||
|
<field name="model">ga.asset.transfer.log</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree string="Asset Transfer Logs" decoration-info="state == 'transit'" decoration-muted="state == 'cancel'" decoration-success="state == 'done'">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="transfer_date"/>
|
||||||
|
<field name="asset_id"/>
|
||||||
|
<field name="source_company_id"/>
|
||||||
|
<field name="target_company_id"/>
|
||||||
|
<field name="user_id"/>
|
||||||
|
<field name="state" widget="badge" decoration-info="state == 'transit'" decoration-success="state == 'done'"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_ga_asset_transfer_log_form" model="ir.ui.view">
|
||||||
|
<field name="name">ga.asset.transfer.log.form</field>
|
||||||
|
<field name="model">ga.asset.transfer.log</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Asset Transfer Log">
|
||||||
|
<header>
|
||||||
|
<button name="action_validate" string="Validate & Receive" type="object" class="btn-primary" invisible="state != 'transit'"/>
|
||||||
|
<button name="action_cancel" string="Cancel" type="object" class="btn-secondary" invisible="state not in ('draft', 'transit')"/>
|
||||||
|
<field name="state" widget="statusbar" statusbar_visible="draft,transit,done"/>
|
||||||
|
</header>
|
||||||
|
<sheet>
|
||||||
|
<div class="oe_title">
|
||||||
|
<h1>
|
||||||
|
<field name="name"/>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="asset_id"/>
|
||||||
|
<field name="transfer_date"/>
|
||||||
|
<field name="user_id"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="source_company_id"/>
|
||||||
|
<field name="target_company_id"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<field name="note" placeholder="Add a note..."/>
|
||||||
|
</sheet>
|
||||||
|
<div class="oe_chatter">
|
||||||
|
<field name="message_follower_ids"/>
|
||||||
|
<field name="activity_ids"/>
|
||||||
|
<field name="message_ids"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_ga_asset_transfer_log" model="ir.actions.act_window">
|
||||||
|
<field name="name">Pending Asset Receipts</field>
|
||||||
|
<field name="res_model">ga.asset.transfer.log</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
<field name="domain">[('state', '=', 'transit')]</field> <!-- Focus on pending ones by default, or maybe all? -->
|
||||||
|
<field name="context">{'search_default_transit': 1}</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
No pending asset transfers found
|
||||||
|
</p><p>
|
||||||
|
When an asset is transferred from another company, it will appear here for validation.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="menu_ga_asset_transfer_log"
|
||||||
|
name="Pending Asset Receipts"
|
||||||
|
parent="account_asset.menu_finance_config_assets"
|
||||||
|
action="action_ga_asset_transfer_log"
|
||||||
|
sequence="15"/>
|
||||||
|
|
||||||
|
<!-- Also add to main Asset menu root if needed, but config seems safe or better under 'Assets' main
|
||||||
|
Let's check where 'account_asset.menu_account_asset' is. Usually Accounting -> Assets -> Assets.
|
||||||
|
Wait, check existing menu structure.
|
||||||
|
-->
|
||||||
|
<!-- Removed Accounting menu as per request -->
|
||||||
|
</odoo>
|
||||||
Binary file not shown.
@ -12,86 +12,27 @@ class GaAssetTransferWizard(models.TransientModel):
|
|||||||
def action_transfer(self):
|
def action_transfer(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if self.target_company_id and self.target_company_id != self.current_company_id:
|
if self.target_company_id and self.target_company_id != self.current_company_id:
|
||||||
old_asset = self.asset_id
|
# Create Transfer Log
|
||||||
|
transfer_log = self.env['ga.asset.transfer.log'].create({
|
||||||
# CASE 1: Asset is Draft or Model -> Simple Move
|
'asset_id': self.asset_id.id,
|
||||||
# No depreciation history to preserve, so we just move it.
|
'source_company_id': self.current_company_id.id,
|
||||||
if old_asset.state in ('draft', 'model'):
|
'target_company_id': self.target_company_id.id,
|
||||||
old_asset.sudo().write({'company_id': self.target_company_id.id})
|
'note': self.note,
|
||||||
if self.note:
|
'state': 'transit',
|
||||||
old_asset.sudo().message_post(body=f"Asset transferred to {self.target_company_id.name}. Note: {self.note}")
|
|
||||||
|
|
||||||
return {
|
|
||||||
'name': 'Transferred Asset',
|
|
||||||
'type': 'ir.actions.act_window',
|
|
||||||
'res_model': 'account.asset',
|
|
||||||
'view_mode': 'form',
|
|
||||||
'res_id': old_asset.id,
|
|
||||||
'target': 'current',
|
|
||||||
}
|
|
||||||
|
|
||||||
# CASE 2: Asset is Running (Open/Parsed) -> Close and Clone
|
|
||||||
# We want to stop the old one and start fresh in new company
|
|
||||||
vals = {
|
|
||||||
'name': old_asset.name,
|
|
||||||
'product_id': old_asset.product_id.id,
|
|
||||||
'asset_code': old_asset.asset_code,
|
|
||||||
'original_value': old_asset.original_value,
|
|
||||||
'already_depreciated_amount_import': old_asset.original_value - old_asset.value_residual,
|
|
||||||
'acquisition_date': old_asset.acquisition_date,
|
|
||||||
'prorata_date': old_asset.prorata_date,
|
|
||||||
'method': old_asset.method,
|
|
||||||
'method_number': old_asset.method_number,
|
|
||||||
'method_period': old_asset.method_period,
|
|
||||||
'method_progress_factor': old_asset.method_progress_factor,
|
|
||||||
'prorata_computation_type': old_asset.prorata_computation_type,
|
|
||||||
'company_id': self.target_company_id.id,
|
|
||||||
'state': 'draft',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Find Asset Model in Target Company to apply Accounts
|
|
||||||
if old_asset.product_id:
|
|
||||||
# Get Product with company context
|
|
||||||
product = old_asset.product_id.with_company(self.target_company_id)
|
|
||||||
account = product.property_account_expense_id or product.categ_id.property_account_expense_categ_id
|
|
||||||
|
|
||||||
if account and account.asset_model:
|
|
||||||
model = account.asset_model
|
|
||||||
vals['model_id'] = model.id
|
|
||||||
# Auto-populate Accounts from Model
|
|
||||||
vals['account_asset_id'] = model.account_asset_id.id
|
|
||||||
vals['account_depreciation_id'] = model.account_depreciation_id.id
|
|
||||||
vals['account_depreciation_expense_id'] = model.account_depreciation_expense_id.id
|
|
||||||
vals['journal_id'] = model.journal_id.id
|
|
||||||
|
|
||||||
# 2. Close the old asset WITHOUT generating Disposal Moves
|
|
||||||
# User request: "no need to use dispose method (gain/loss account)"
|
|
||||||
# We simply stop future depreciation and archive the old asset.
|
|
||||||
# NOTE: The Asset Value remains on the old company's Balance Sheet until manually adjusted/transferred.
|
|
||||||
|
|
||||||
# Cancel future draft moves (using sudo to bypass company rules if needed)
|
|
||||||
old_asset.depreciation_move_ids.filtered(lambda m: m.state == 'draft').with_context(force_delete=True).sudo().unlink()
|
|
||||||
|
|
||||||
# Close and Archive (using sudo to ensure we can modify the record even if we are switching context)
|
|
||||||
old_asset.sudo().write({
|
|
||||||
'state': 'close',
|
|
||||||
'active': False,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
old_asset.sudo().message_post(body=f"Asset transferred to {self.target_company_id.name}. Auto-disposal skipped.")
|
# Lock Asset
|
||||||
|
self.asset_id.sudo().write({'in_transit': True})
|
||||||
|
self.asset_id.message_post(body=f"Asset transfer initiated to {self.target_company_id.name}. Waiting for validation. Ref: {transfer_log.name}")
|
||||||
|
|
||||||
# 3. Create the new asset in target company (using sudo to create in a company we might not be active in)
|
|
||||||
new_asset = self.env['account.asset'].sudo().create(vals)
|
|
||||||
new_asset.sudo().message_post(body=f"Asset transferred from {self.current_company_id.name}. Note: {self.note}")
|
|
||||||
|
|
||||||
# 4. Open the new asset
|
|
||||||
return {
|
return {
|
||||||
'name': 'Transferred Asset',
|
'type': 'ir.actions.client',
|
||||||
'type': 'ir.actions.act_window',
|
'tag': 'display_notification',
|
||||||
'res_model': 'account.asset',
|
'params': {
|
||||||
'view_mode': 'form',
|
'title': 'Transfer Initiated',
|
||||||
'res_id': new_asset.id,
|
'message': f"Asset transfer to {self.target_company_id.name} is now pending validation.",
|
||||||
'target': 'current',
|
'sticky': False,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {'type': 'ir.actions.act_window_close'}
|
return {'type': 'ir.actions.act_window_close'}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user