diff --git a/picking_policy_per_customer/__init__.py b/picking_policy_per_customer/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/picking_policy_per_customer/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/picking_policy_per_customer/__manifest__.py b/picking_policy_per_customer/__manifest__.py new file mode 100644 index 0000000..c64195c --- /dev/null +++ b/picking_policy_per_customer/__manifest__.py @@ -0,0 +1,23 @@ +{ + 'name': 'Customer Specific Picking Policy', + 'version': '18.0.1.0.0', + 'category': 'Sales', + 'summary': 'Configure picking policy (delivery orders) per customer', + 'description': """ + This module allows you to set specific picking policies per customer. + It extends the default global picking policy setting to be configurable at the customer level. + """, + 'author': 'Bemade', + 'website': 'https://bemade.org', + 'depends': [ + 'sale', + 'stock', + ], + 'data': [ + 'views/res_partner_views.xml', + ], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} \ No newline at end of file diff --git a/picking_policy_per_customer/models/__init__.py b/picking_policy_per_customer/models/__init__.py new file mode 100644 index 0000000..17c6cc8 --- /dev/null +++ b/picking_policy_per_customer/models/__init__.py @@ -0,0 +1,2 @@ +from . import res_partner +from . import sale_order diff --git a/picking_policy_per_customer/models/res_partner.py b/picking_policy_per_customer/models/res_partner.py new file mode 100644 index 0000000..b014e9f --- /dev/null +++ b/picking_policy_per_customer/models/res_partner.py @@ -0,0 +1,19 @@ +from odoo import fields, models + + +class ResPartner(models.Model): + """ + Extends the partner model to add customer-specific picking policy preferences. + + This extension allows setting a default picking (shipping) policy at the customer level, + which will be used as the default value when creating sales orders for this customer. + """ + _inherit = 'res.partner' + + picking_policy = fields.Selection([ + ('direct', 'Deliver each product when available'), + ('one', 'Deliver all products at once')], + string='Shipping Policy', + help='Select how to handle multi-product deliveries:\n' + '- Deliver each product when available: products will be shipped as soon as they are available\n' + '- Deliver all products at once: products will be shipped altogether when all of them are available') diff --git a/picking_policy_per_customer/models/sale_order.py b/picking_policy_per_customer/models/sale_order.py new file mode 100644 index 0000000..efcf08f --- /dev/null +++ b/picking_policy_per_customer/models/sale_order.py @@ -0,0 +1,19 @@ +from odoo import api, models + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + + @api.onchange('partner_id') + def _onchange_partner_id(self): + if self.partner_id and self.partner_id.picking_policy: + self.picking_policy = self.partner_id.picking_policy + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if vals.get('partner_id'): + partner = self.env['res.partner'].browse(vals['partner_id']) + if partner.picking_policy: + vals['picking_policy'] = partner.picking_policy + return super().create(vals_list) \ No newline at end of file diff --git a/picking_policy_per_customer/views/res_partner_views.xml b/picking_policy_per_customer/views/res_partner_views.xml new file mode 100644 index 0000000..873f372 --- /dev/null +++ b/picking_policy_per_customer/views/res_partner_views.xml @@ -0,0 +1,13 @@ + + + + res.partner.form.inherit.picking.policy + res.partner + + + + + + + + diff --git a/purchase_customer_requisition/__init__.py b/purchase_customer_requisition/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/purchase_customer_requisition/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/purchase_customer_requisition/__manifest__.py b/purchase_customer_requisition/__manifest__.py new file mode 100644 index 0000000..62997ec --- /dev/null +++ b/purchase_customer_requisition/__manifest__.py @@ -0,0 +1,27 @@ +{ + 'name': 'Purchase Customer Requisition', + 'version': '1.0', + 'category': 'Purchase', + 'summary': 'Link customer requisition references to purchase orders', + 'description': """ + This module allows to: + * Store customer-specific requisition references for suppliers + * Automatically add these references to purchase order lines + * Track customer requisition numbers across purchase orders + """, + 'license': 'LGPL-3', + 'depends': [ + 'purchase', + 'sale_purchase', + 'purchase_requisition' + ], + 'data': [ + 'security/ir.model.access.csv', + 'views/customer_supplier_requisition_views.xml', + 'views/purchase_views.xml', + 'views/purchase_requisition_views.xml', + ], + 'installable': True, + 'application': False, + 'auto_install': False, +} \ No newline at end of file diff --git a/purchase_customer_requisition/models/__init__.py b/purchase_customer_requisition/models/__init__.py new file mode 100644 index 0000000..cddeb79 --- /dev/null +++ b/purchase_customer_requisition/models/__init__.py @@ -0,0 +1,3 @@ +from . import customer_supplier_requisition +from . import purchase_order_line +from . import purchase_requisition diff --git a/purchase_customer_requisition/models/customer_supplier_requisition.py b/purchase_customer_requisition/models/customer_supplier_requisition.py new file mode 100644 index 0000000..cc5efdd --- /dev/null +++ b/purchase_customer_requisition/models/customer_supplier_requisition.py @@ -0,0 +1,37 @@ +from odoo import models, fields, api + +class CustomerSupplierRequisition(models.Model): + _name = 'customer.supplier.requisition' + _description = 'Customer Supplier Requisition Reference' + + customer_id = fields.Many2one( + comodel_name='res.partner', + string='Customer', + required=True, + domain=[ + ('customer_rank', '>', 0) + ] + ) + + supplier_id = fields.Many2one( + comodel_name='res.partner', + string='Supplier', + required=True, + domain=[ + ('supplier_rank', '>', 0)] + ) + + requisition_ref = fields.Char( + string='Requisition Reference', + required=True, + help='Reference number used by the supplier for this customer' + ) + + active = fields.Boolean( + default=True + ) + + _sql_constraints = [ + ('unique_customer_supplier', 'unique(customer_id, supplier_id)', + 'A requisition reference already exists for this customer-supplier pair!') + ] diff --git a/purchase_customer_requisition/models/purchase_order_line.py b/purchase_customer_requisition/models/purchase_order_line.py new file mode 100644 index 0000000..49f4013 --- /dev/null +++ b/purchase_customer_requisition/models/purchase_order_line.py @@ -0,0 +1,32 @@ +from odoo import models, fields, api + +class PurchaseOrderLine(models.Model): + _inherit = 'purchase.order.line' + + customer_requisition_ref = fields.Char( + string='Customer Requisition Ref', + compute='_compute_customer_requisition_ref', + store=True, + help='Customer requisition reference for this supplier' + ) + + @api.depends('sale_line_id.order_id.partner_id', 'order_id.partner_id') + def _compute_customer_requisition_ref(self): + for line in self: + if line.sale_line_id and line.sale_line_id.order_id.partner_id and line.order_id.partner_id: + requisition = self.env['customer.supplier.requisition'].search([ + ('customer_id', '=', line.sale_line_id.order_id.partner_id.id), + ('supplier_id', '=', line.order_id.partner_id.id) + ], limit=1) + line.customer_requisition_ref = requisition.requisition_ref if requisition else False + else: + line.customer_requisition_ref = False + + @api.model_create_multi + def create(self, vals_list): + lines = super().create(vals_list) + for line in lines: + if line.customer_requisition_ref: + if line.name: + line.name = f"[{line.customer_requisition_ref}] {line.name}" + return lines diff --git a/purchase_customer_requisition/models/purchase_requisition.py b/purchase_customer_requisition/models/purchase_requisition.py new file mode 100644 index 0000000..e44a579 --- /dev/null +++ b/purchase_customer_requisition/models/purchase_requisition.py @@ -0,0 +1,41 @@ +from odoo import models, fields, api + +class PurchaseRequisition(models.Model): + _inherit = 'purchase.requisition' + + customer_id = fields.Many2one( + comodel_name='res.partner', + string='Customer', + domain=[('customer_rank', '>', 0)], + help='Customer for whom this requisition is created' + ) + + customer_requisition_ref = fields.Char( + string='Customer Requisition Ref', + compute='_compute_customer_requisition_ref', + store=True, + help='Customer requisition reference' + ) + + @api.depends('customer_id', 'vendor_id') + def _compute_customer_requisition_ref(self): + for requisition in self: + if requisition.customer_id and requisition.vendor_id: + ref = self.env['customer.supplier.requisition'].search([ + ('customer_id', '=', requisition.customer_id.id), + ('supplier_id', '=', requisition.vendor_id.id) + ], limit=1) + requisition.customer_requisition_ref = ref.requisition_ref if ref else False + else: + requisition.customer_requisition_ref = False + + def action_in_progress(self): + res = super().action_in_progress() + for requisition in self: + if requisition.customer_requisition_ref: + # Update all related PO lines description + for po in requisition.purchase_ids: + for line in po.order_line: + if line.name and not line.name.startswith(f'[{requisition.customer_requisition_ref}]'): + line.name = f'[{requisition.customer_requisition_ref}] {line.name}' + return res diff --git a/purchase_customer_requisition/security/ir.model.access.csv b/purchase_customer_requisition/security/ir.model.access.csv new file mode 100644 index 0000000..e37c325 --- /dev/null +++ b/purchase_customer_requisition/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_customer_supplier_requisition_user,customer.supplier.requisition.user,model_customer_supplier_requisition,purchase.group_purchase_user,1,0,0,0 +access_customer_supplier_requisition_manager,customer.supplier.requisition.manager,model_customer_supplier_requisition,purchase.group_purchase_manager,1,1,1,1 diff --git a/purchase_customer_requisition/views/customer_supplier_requisition_views.xml b/purchase_customer_requisition/views/customer_supplier_requisition_views.xml new file mode 100644 index 0000000..cae46ee --- /dev/null +++ b/purchase_customer_requisition/views/customer_supplier_requisition_views.xml @@ -0,0 +1,52 @@ + + + + customer.supplier.requisition.list + customer.supplier.requisition + + + + + + + + + + + customer.supplier.requisition.form + customer.supplier.requisition + +
+ + + + + + + + + + + + +
+
+
+ + + Customer Supplier Requisitions + customer.supplier.requisition + list,form + +

+ Create your first customer supplier requisition reference +

+
+
+ + +
diff --git a/purchase_customer_requisition/views/purchase_requisition_views.xml b/purchase_customer_requisition/views/purchase_requisition_views.xml new file mode 100644 index 0000000..d4cb6c2 --- /dev/null +++ b/purchase_customer_requisition/views/purchase_requisition_views.xml @@ -0,0 +1,25 @@ + + + + purchase.requisition.form.inherit + purchase.requisition + + + + + + + + + + + purchase.requisition.list.inherit + purchase.requisition + + + + + + + + diff --git a/purchase_customer_requisition/views/purchase_views.xml b/purchase_customer_requisition/views/purchase_views.xml new file mode 100644 index 0000000..04b38f1 --- /dev/null +++ b/purchase_customer_requisition/views/purchase_views.xml @@ -0,0 +1,16 @@ + + + + purchase.order.form.inherit + purchase.order + + + + + + + + + + +