From a40d7597d8b32bc434881fa6c4e9ed9c83339afe Mon Sep 17 00:00:00 2001 From: younes Date: Thu, 17 Jul 2025 22:09:30 +0100 Subject: [PATCH] IMP purchase request logic --- .../purchase_custom_stock/i18n/ar_001.po | 27 +++- .../models/purchase_request.py | 100 +++++-------- .../wizards/picking_purchase_request.py | 135 +++++++++++------- .../wizards/picking_purchase_request.xml | 3 +- 4 files changed, 147 insertions(+), 118 deletions(-) diff --git a/odex25_purchase/purchase_custom_stock/i18n/ar_001.po b/odex25_purchase/purchase_custom_stock/i18n/ar_001.po index 24415cef0..40ef9b43b 100644 --- a/odex25_purchase/purchase_custom_stock/i18n/ar_001.po +++ b/odex25_purchase/purchase_custom_stock/i18n/ar_001.po @@ -588,4 +588,29 @@ msgstr "المستند المصدر" #. module: purchase_custom_stock #: model:ir.model,name:purchase_custom_stock.model_asset_custody_line msgid "asset.custody.line" -msgstr "بند أصل" \ No newline at end of file +msgstr "بند أصل" + +#. module: purchase_custom_stock +#: code:addons/purchase_custom_stock/models/purchase_request.py:0 +#, python-format +msgid "Picking Options" +msgstr "خيارات الاستلام" + +#. module: purchase_custom_stock +#: code:addons/purchase_custom_stock/wizards/picking_purchase_request.py:0 +#, python-format +msgid "Warning" +msgstr "تحذير" + +#. module: purchase_custom_stock +#: code:addons/purchase_custom_stock/wizards/picking_purchase_request.py:0 +#, python-format +msgid "" +"If you choose this option, consumable and service products will not be " +"purchased" +msgstr "إذا اخترت هذا الخيار، فلن يتم شراء المنتجات الاستهلاكية أو المنتجات الخدمية" + +#. module: purchase_custom_stock +#: model_terms:ir.ui.view,arch_db:purchase_custom_stock.purchase_request_picking_wizard_view_form +msgid "Delivery and Close" +msgstr "صرف المتوفر وإغلاق الطلب" \ No newline at end of file diff --git a/odex25_purchase/purchase_custom_stock/models/purchase_request.py b/odex25_purchase/purchase_custom_stock/models/purchase_request.py index 4694d6240..7806f644e 100644 --- a/odex25_purchase/purchase_custom_stock/models/purchase_request.py +++ b/odex25_purchase/purchase_custom_stock/models/purchase_request.py @@ -242,80 +242,44 @@ class PurchaseRequest(models.Model): raise ValidationError(_("Can't Confirm Request With No Item!")) if not self.department_id: raise ValidationError(_("Please Select department for employee")) - picking_id = self.env.ref('purchase_custom_stock.stock_picking_type_stock') + storable_lines = self.line_ids.filtered(lambda l: l.product_id.type == 'product') + asset_lines = self.line_ids.filtered(lambda l: l.product_id.asset_ok) + consu_lines = self.line_ids.filtered(lambda l: l.product_id.type == 'consu') + consu_non_asset_lines = self.line_ids.filtered( + lambda l: l.product_id.type == 'consu' and not l.product_id.asset_ok) + relevant_lines = storable_lines | asset_lines | consu_non_asset_lines + has_available = any(l.available_qty > 0 for l in relevant_lines) + has_insufficient_qty = any(l.qty > l.available_qty for l in relevant_lines) - available = False - if any(self.line_ids.filtered(lambda line: line.product_id.type in ['product', 'consu'])): - storable_product_lines = self.line_ids.filtered(lambda line: line.product_id.type == 'product') - asset_product_lines = self.line_ids.filtered(lambda line: line.product_id.asset_ok) - consu_product_not_asset_lines = self.line_ids.filtered( - lambda line: line.product_id.type == 'consu' and not line.product_id.asset_ok) - non_storable_product = self.line_ids - storable_product_lines - asset_product_lines - consu_product_not_asset_lines - if any(storable_product_lines.filtered(lambda line: line.available_qty > 0)) or any( - consu_product_not_asset_lines.filtered(lambda line: line.available_qty > 0)) or any( - asset_product_lines.filtered(lambda line: line.available_qty > 0)): - available = True - if any(storable_product_lines.filtered( - lambda store_line: store_line.qty > store_line.available_qty)) or any( - asset_product_lines.filtered(lambda asset_line: asset_line.qty > asset_line.available_qty)) or any( - consu_product_not_asset_lines.filtered(lambda asset_line: asset_line.qty > asset_line.available_qty)): - if self.has_asset_product_line: - self.create_asset_custody_lines() - context = {} - view = self.env.ref('purchase_custom_stock.purchase_request_picking_wizard_view_form') - wiz = self.env['purchase.request_picking.wizard'] - context['default_request_id'] = self.id - context['default_is_available'] = available - storable_product = self.line_ids.filtered(lambda line: line.product_id.type == 'product') - context['default_request_line_ids'] = [ - (6, 0, self.line_ids.ids)] - - return { - 'name': _('Picking Options'), - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'purchase.request_picking.wizard', - 'views': [(view.id, 'form')], - 'view_id': view.id, - 'target': 'new', - 'context': context, - } - else: - product_lines = storable_product_lines + consu_product_not_asset_lines - if product_lines: - move_vals = [] - for line in product_lines: - move_vals.append((0, 0, { - "product_id": line.product_id.id, - "name": line.product_id.name, - "product_uom": line.product_id.uom_id.id, - 'product_uom_qty': line.qty, - - })) - line.qty_purchased = 0 - picking_vals = { - "picking_type_id": self.env.ref('purchase_custom_stock.stock_picking_type_stock').id, - "origin": self.name, - "location_id": self.location_id.id, - "location_dest_id": picking_id.default_location_dest_id.id, - 'move_lines': move_vals, - } - picking_id = self.env['stock.picking'].create(picking_vals) - self.picking_id = picking_id.id - if self.has_asset_product_line: - self.create_asset_custody_lines() - if non_storable_product: - for rec in non_storable_product: - rec.qty_purchased = rec.qty - self.write({'state': 'waiting'}) - else: - self.write({'state': 'employee'}) + if storable_lines or consu_lines: + if self.has_asset_product_line: + self.create_asset_custody_lines() + return self._open_picking_wizard(has_available if has_insufficient_qty else False) else: for line in self.line_ids: line.qty_purchased = line.qty self.write({'state': 'waiting'}) + def _open_picking_wizard(self, is_available): + context = { + 'default_request_id': self.id, + 'default_is_available': is_available, + 'default_request_line_ids': [(6, 0, self.line_ids.ids)] + } + + view = self.env.ref('purchase_custom_stock.purchase_request_picking_wizard_view_form') + + return { + 'name': _('Picking Options'), + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'purchase.request_picking.wizard', + 'views': [(view.id, 'form')], + 'view_id': view.id, + 'target': 'new', + 'context': context, + } def open_picking(self): return { diff --git a/odex25_purchase/purchase_custom_stock/wizards/picking_purchase_request.py b/odex25_purchase/purchase_custom_stock/wizards/picking_purchase_request.py index 70b1a856b..74eec8833 100644 --- a/odex25_purchase/purchase_custom_stock/wizards/picking_purchase_request.py +++ b/odex25_purchase/purchase_custom_stock/wizards/picking_purchase_request.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models +from odoo import api, fields, models, _ +from odoo.exceptions import Warning class PurcahseRefues(models.TransientModel): @@ -18,58 +19,77 @@ class PurcahseRefues(models.TransientModel): self.show_purchase_only = all(line.available_qty <= 0 for line in self.request_line_ids) def delivery_close(self): - picking_id = self.env.ref('purchase_custom_stock.stock_picking_type_stock') - picking_vals = { - "picking_type_id": self.env.ref('purchase_custom_stock.stock_picking_type_stock').id, - "origin": self.request_id.name, - "location_id": self.request_id.location_id.id, - "location_dest_id": picking_id.default_location_dest_id.id - } - - move_vals = [] - for line in self.request_line_ids: - move_vals.append((0, 0, { - "product_id": line.product_id.id, - "name": line.product_id.name, - "product_uom": line.product_id.uom_id.id, - 'product_uom_qty': line.qty, - })) - picking_vals.update({'move_lines': move_vals}) - picking_id = self.env['stock.picking'].create(picking_vals) - self.request_id.picking_id = picking_id.id - self.request_id.write({'state': 'employee'}) - - def delivery_purchase(self): if self.request_line_ids.filtered( - lambda line: line.product_id.type == 'product') or self.request_line_ids.filtered( - lambda line: line.product_id.type == 'consu' and not line.product_id.asset_ok): - picking_id = self.env.ref('purchase_custom_stock.stock_picking_type_stock') + lambda line: line.product_id.type == 'product'): + picking_type = self.env.ref('purchase_custom_stock.stock_picking_type_stock') picking_vals = { - "picking_type_id": self.env.ref('purchase_custom_stock.stock_picking_type_stock').id, + "picking_type_id": picking_type.id, "origin": self.request_id.name, "location_id": self.request_id.location_id.id, - "location_dest_id": picking_id.default_location_dest_id.id + "location_dest_id": picking_type.default_location_dest_id.id } move_vals = [] - for line in self.request_line_ids.filtered(lambda line: line.product_id.type in ['product', 'consu']): + + for line in self.request_line_ids.filtered(lambda line: line.product_id.type in ['product']): if not line.product_id.asset_ok: - if line.qty < line.available_qty: + if min(line.qty, line.available_qty): move_vals.append((0, 0, { "product_id": line.product_id.id, "name": line.product_id.name, "product_uom": line.product_id.uom_id.id, - 'product_uom_qty': line.qty, + 'product_uom_qty': min(line.qty, line.available_qty), })) line.qty_purchased = 0 + picking_vals.update({'move_lines': move_vals}) + picking_id = self.env['stock.picking'].create(picking_vals) + self.request_id.picking_id = picking_id.id + service_consumable_lines = self.request_line_ids.filtered( + lambda line: line.product_id.type == 'service' or + (line.product_id.type == 'consu' and not line.product_id.asset_ok) + ) + self.request_id.write({'state': 'employee'}) + if service_consumable_lines: + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': _('Warning'), + 'message': _( + "If you choose this option, consumable and service products will not be purchased"), + 'type': 'warning', + 'sticky': True, + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + + def delivery_purchase(self): + if self.request_line_ids.filtered( + lambda line: line.product_id.type in ('product', 'consu') and ( + line.product_id.type != 'consu' or not line.product_id.asset_ok + ) + ): + picking_type = self.env.ref('purchase_custom_stock.stock_picking_type_stock') + picking_vals = { + "picking_type_id": picking_type.id, + "origin": self.request_id.name, + "location_id": self.request_id.location_id.id, + "location_dest_id": picking_type.default_location_dest_id.id + } + + move_vals = [] + filtered_lines = self.request_line_ids.filtered(lambda line: line.product_id.type in ['product', 'consu']) + for line in filtered_lines: + if not line.product_id.asset_ok: + move_vals.append((0, 0, { + "product_id": line.product_id.id, + "name": line.product_id.name, + "product_uom": line.product_id.uom_id.id, + 'product_uom_qty': line.qty, + })) + if line.qty < line.available_qty: + line.qty_purchased = 0 else: - if line.available_qty > 0: - move_vals.append((0, 0, { - "product_id": line.product_id.id, - "name": line.product_id.name, - "product_uom": line.product_id.uom_id.id, - 'product_uom_qty': line.qty, - })) line.qty_purchased = line.qty - line.available_qty picking_vals.update({'move_lines': move_vals}) picking_id = self.env['stock.picking'].create(picking_vals) @@ -83,14 +103,16 @@ class PurcahseRefues(models.TransientModel): def convert_purchase(self): if self.request_line_ids.filtered( - lambda line: line.product_id.type == 'product') or self.request_line_ids.filtered( - lambda line: line.product_id.type == 'consu' and not line.product_id.asset_ok): - picking_id = self.env.ref('purchase_custom_stock.stock_picking_type_stock') + lambda line: line.product_id.type in ('product', 'consu') and ( + line.product_id.type != 'consu' or not line.product_id.asset_ok + ) + ): + picking_type = self.env.ref('purchase_custom_stock.stock_picking_type_stock') picking_vals = { - "picking_type_id": self.env.ref('purchase_custom_stock.stock_picking_type_stock').id, + "picking_type_id": picking_type.id, "origin": self.request_id.name, "location_id": self.request_id.location_id.id, - "location_dest_id": picking_id.default_location_dest_id.id + "location_dest_id": picking_type.default_location_dest_id.id } move_vals = [] @@ -105,9 +127,26 @@ class PurcahseRefues(models.TransientModel): picking_vals.update({'move_lines': move_vals}) picking_id = self.env['stock.picking'].create(picking_vals) self.request_id.picking_id = picking_id.id - init_active = self.env['ir.module.module'].sudo().search( - [('name', '=', 'initial_engagement_budget'), ('state', '=', 'installed')], limit=1) - init_budget = True if init_active else False + storable_lines = self.request_line_ids.filtered(lambda l: l.product_id.type == 'product') + asset_lines = self.request_line_ids.filtered(lambda l: l.product_id.asset_ok) + consu_non_asset_lines = self.request_line_ids.filtered( + lambda l: l.product_id.type == 'consu' and not l.product_id.asset_ok + ) + relevant_lines = storable_lines | asset_lines | consu_non_asset_lines + non_storable_product = self.request_line_ids - storable_lines - asset_lines - consu_non_asset_lines + fully_available = all(l.qty <= l.available_qty for l in relevant_lines) + for line in self.request_line_ids: - line.qty_purchased = line.qty - line.available_qty - self.request_id.write({'state': 'wait_for_send' if init_budget else 'waiting'}) + line.qty_purchased = line.qty if fully_available else line.qty - line.available_qty + if fully_available: + # self = self.with_context(fully_available=True) + if non_storable_product: + self.request_id.write({'state': 'waiting'}) + else: + self.request_id.write({'state': 'employee'}) + else: + init_active = self.env['ir.module.module'].sudo().search( + [('name', '=', 'initial_engagement_budget'), ('state', '=', 'installed')], limit=1) + init_budget = True if init_active else False + self.request_id.write({'state': 'wait_for_send' if init_budget else 'waiting'}) + return fully_available diff --git a/odex25_purchase/purchase_custom_stock/wizards/picking_purchase_request.xml b/odex25_purchase/purchase_custom_stock/wizards/picking_purchase_request.xml index 1b8885bfa..caaaedd12 100644 --- a/odex25_purchase/purchase_custom_stock/wizards/picking_purchase_request.xml +++ b/odex25_purchase/purchase_custom_stock/wizards/picking_purchase_request.xml @@ -10,7 +10,8 @@