first commit

This commit is contained in:
Suherdy Yacob 2026-02-10 14:53:13 +07:00
commit 70ae5ea804
10 changed files with 145 additions and 0 deletions

1
__init__.py Normal file
View File

@ -0,0 +1 @@
from . import models

18
__manifest__.py Normal file
View File

@ -0,0 +1,18 @@
{
'name': 'Approval Create WH to Prep Move',
'version': '1.0',
'category': 'Inventory/Approvals',
'summary': 'Create Inventory Transfer from Approval Request',
'description': """
This module adds a new approval type "Create WH to Prep Move" to the Approvals app.
When approved, it allows users to create an inventory transfer with the operation
"Brigjend Katamso: WH to Prep (Send)" and destination "Physical Locations/Inter-warehouse transit".
""",
'depends': ['approvals', 'stock'],
'data': [
'views/approval_request_views.xml',
],
'installable': True,
'application': False,
'license': 'LGPL-3',
}

Binary file not shown.

2
models/__init__.py Normal file
View File

@ -0,0 +1,2 @@
from . import approval_category
from . import approval_request

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,12 @@
from odoo import api, fields, models
class ApprovalCategory(models.Model):
_inherit = 'approval.category'
approval_type = fields.Selection(selection_add=[('wh_prep_move', 'Create WH to Prep Move')])
@api.onchange('approval_type')
def _onchange_approval_type(self):
if self.approval_type == 'wh_prep_move':
self.has_product = 'required'
self.has_quantity = 'required'

View File

@ -0,0 +1,86 @@
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.tools.misc import clean_context
from markupsafe import Markup
class ApprovalRequest(models.Model):
_inherit = 'approval.request'
picking_ids = fields.Many2many('stock.picking',compute='_compute_picking_ids', string='Transfers')
picking_count = fields.Integer(compute='_compute_picking_count')
def _compute_picking_ids(self):
for request in self:
request.picking_ids = self.env['stock.picking'].search([('origin', '=', request.name)]) if request.name else False
@api.depends('picking_ids')
def _compute_picking_count(self):
for request in self:
request.picking_count = len(request.picking_ids)
def action_create_wh_prep_move(self):
self.ensure_one()
if self.picking_count > 0:
return
op_type_name = "Brigjend Katamso: WH to Prep (Send)"
dest_loc_name = "Physical Locations/Inter-warehouse transit"
# Find Operation Type
picking_type = self.env['stock.picking.type'].search([('name', '=', op_type_name)], limit=1)
if not picking_type:
# Fallback: search by display_name if name isn't exact
picking_types = self.env['stock.picking.type'].search([])
for pt in picking_types:
if op_type_name in pt.display_name:
picking_type = pt
break
if not picking_type:
raise UserError(_("Operation Type '%s' not found. Please contact administrator.") % op_type_name)
# Find Destination Location
dest_loc = self.env['stock.location'].search([('complete_name', '=', dest_loc_name)], limit=1)
if not dest_loc:
raise UserError(_("Destination Location '%s' not found. Please contact administrator.") % dest_loc_name)
if not self.product_line_ids:
raise UserError(_("You must select products to create a transfer."))
picking_vals = {
'picking_type_id': picking_type.id,
'location_id': picking_type.default_location_src_id.id,
'location_dest_id': dest_loc.id,
'origin': self.name,
'partner_id': self.partner_id.id,
'move_ids': [],
}
for line in self.product_line_ids:
move_vals = {
'description_picking': line.description,
'product_id': line.product_id.id,
'product_uom_qty': line.quantity,
'product_uom': line.product_uom_id.id,
'location_id': picking_type.default_location_src_id.id,
'location_dest_id': dest_loc.id,
}
picking_vals['move_ids'].append((0, 0, move_vals))
picking = self.env['stock.picking'].create(picking_vals)
picking.action_confirm() # Confirm the picking to reserve stock if possible
msg = Markup(_("Created Inventory Transfer: <a href='#' data-oe-model='stock.picking' data-oe-id='%d'>%s</a>")) % (picking.id, picking.name)
self.message_post(body=msg)
def action_open_wh_prep_move(self):
self.ensure_one()
action = {
'name': _('Transfers'),
'type': 'ir.actions.act_window',
'res_model': 'stock.picking',
'view_mode': 'list,form',
'domain': [('origin', '=', self.name)],
'context': clean_context(self.env.context),
}
return action

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="approval_wh_prep_move_request_view_form_inherit" model="ir.ui.view">
<field name="name">approval.wh.prep.move.request.view.form.inherit</field>
<field name="model">approval.request</field>
<field name="inherit_id" ref="approvals.approval_request_view_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='action_get_attachment_view']" position="after">
<button name="action_open_wh_prep_move" type="object"
groups="stock.group_stock_user"
class="oe_stat_button" icon="fa-truck"
invisible="picking_count == 0">
<field name="picking_count" string="Transfers"
groups="stock.group_stock_user" widget="statinfo"/>
</button>
</xpath>
<xpath expr="//button[@name='action_confirm']" position="after">
<button name="action_create_wh_prep_move" type="object"
groups="stock.group_stock_user"
string="Create WH to Prep Move" class="btn-primary"
data-hotkey="g"
invisible="approval_type != 'wh_prep_move' or request_status != 'approved' or picking_count &gt; 0"/>
</xpath>
</field>
</record>
</odoo>