Initial commit
This commit is contained in:
3
sale_order_to_purchase_order_app/models/__init__.py
Normal file
3
sale_order_to_purchase_order_app/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import sale_order_to_purchase_order_app
|
||||
@@ -0,0 +1,243 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
custom_purchase_count = fields.Integer(
|
||||
string='Purchase',
|
||||
compute='_compute_custom_purchase_count'
|
||||
)
|
||||
|
||||
def _compute_custom_purchase_count(self):
|
||||
for so in self:
|
||||
po_count = self.env['purchase.order'].search_count([
|
||||
('sale_ord_id', '=', so.id)
|
||||
])
|
||||
so.custom_purchase_count = po_count
|
||||
|
||||
def action_view_custom_purchase(self):
|
||||
"""Open the list of purchase orders linked to this sale order"""
|
||||
purchases = self.env['purchase.order'].search([
|
||||
('sale_ord_id', '=', self.id)
|
||||
])
|
||||
return {
|
||||
'name': _('Purchase Order'),
|
||||
'view_mode': 'list,form',
|
||||
'res_model': 'purchase.order',
|
||||
'domain': [('id', 'in', purchases.ids)],
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_inherit = 'purchase.order'
|
||||
|
||||
sale_ord_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string='Sale Order',
|
||||
readonly=True,
|
||||
help='The sale order from which this purchase order was created'
|
||||
)
|
||||
|
||||
marked_for = fields.Char(
|
||||
string='Marked For',
|
||||
readonly=True,
|
||||
help='The customer/person this purchase order is marked for (from Sales Order)'
|
||||
)
|
||||
|
||||
custom_sale_count = fields.Integer(
|
||||
string='Sales',
|
||||
compute='_compute_custom_sale_count'
|
||||
)
|
||||
|
||||
def _compute_custom_sale_count(self):
|
||||
for po in self:
|
||||
if po.sale_ord_id:
|
||||
po.custom_sale_count = 1
|
||||
else:
|
||||
po.custom_sale_count = 0
|
||||
|
||||
def action_view_linked_sale_order(self):
|
||||
"""Open the linked sale order"""
|
||||
self.ensure_one()
|
||||
if not self.sale_ord_id:
|
||||
raise UserError(_("No Sale Order is linked to this Purchase Order."))
|
||||
return {
|
||||
'name': _('Sale Order'),
|
||||
'view_mode': 'form',
|
||||
'res_model': 'sale.order',
|
||||
'res_id': self.sale_ord_id.id,
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
||||
def _open_match_wizard(self, search_hint=''):
|
||||
"""Open the match sale order wizard for manual selection"""
|
||||
wizard = self.env['match.sale.order.wiz'].create({
|
||||
'purchase_order_id': self.id,
|
||||
'search_hint': search_hint,
|
||||
})
|
||||
return {
|
||||
'name': _('Match Sale Order'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'match.sale.order.wiz',
|
||||
'res_id': wizard.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
def action_match_sale_order(self):
|
||||
"""
|
||||
Match this PO to a Sale Order based on x_marked_for field.
|
||||
If no match or multiple matches, opens a wizard for manual selection.
|
||||
"""
|
||||
self.ensure_one()
|
||||
import re
|
||||
|
||||
if self.sale_ord_id:
|
||||
raise UserError(_("This Purchase Order is already linked to Sale Order: %s") % self.sale_ord_id.name)
|
||||
|
||||
# Get the x_marked_for value
|
||||
marked_for_value = getattr(self, 'x_marked_for', None)
|
||||
|
||||
# If no x_marked_for, open wizard directly for manual selection
|
||||
if not marked_for_value:
|
||||
return self._open_match_wizard('')
|
||||
|
||||
matching_partners = None
|
||||
marked_for_str = str(marked_for_value)
|
||||
search_hint = marked_for_str
|
||||
|
||||
# Check if x_marked_for contains a partner ID reference like "res.partner(11519,)"
|
||||
partner_id_match = re.search(r'res\.partner\((\d+)', marked_for_str)
|
||||
if partner_id_match:
|
||||
partner_id = int(partner_id_match.group(1))
|
||||
partner = self.env['res.partner'].browse(partner_id).exists()
|
||||
if partner:
|
||||
matching_partners = partner
|
||||
search_hint = partner.name # Use actual name for search hint
|
||||
|
||||
# If not a partner ID reference, search by name
|
||||
if not matching_partners:
|
||||
matching_partners = self.env['res.partner'].search([
|
||||
'|',
|
||||
('name', 'ilike', marked_for_str),
|
||||
('display_name', 'ilike', marked_for_str)
|
||||
])
|
||||
|
||||
# If no matching partners found, open wizard for manual selection
|
||||
if not matching_partners:
|
||||
return self._open_match_wizard(search_hint)
|
||||
|
||||
# Find Sale Orders for these partners
|
||||
matching_sales = self.env['sale.order'].search([
|
||||
('partner_id', 'in', matching_partners.ids)
|
||||
])
|
||||
|
||||
# If no Sale Orders found, open wizard for manual selection
|
||||
if not matching_sales:
|
||||
return self._open_match_wizard(matching_partners[0].name if matching_partners else search_hint)
|
||||
|
||||
# If multiple Sale Orders, open wizard for manual selection
|
||||
if len(matching_sales) > 1:
|
||||
return self._open_match_wizard(matching_partners[0].name if matching_partners else search_hint)
|
||||
|
||||
# Exactly one match - link it automatically
|
||||
customer_name = matching_partners[0].name
|
||||
self.write({
|
||||
'sale_ord_id': matching_sales.id,
|
||||
'marked_for': customer_name,
|
||||
})
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('Success'),
|
||||
'message': _('Linked to Sale Order: %s') % matching_sales.name,
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
}
|
||||
}
|
||||
|
||||
def action_batch_match_sale_orders(self):
|
||||
"""
|
||||
Batch match multiple POs to Sale Orders based on x_marked_for field.
|
||||
Called from list view action.
|
||||
"""
|
||||
import re
|
||||
matched = 0
|
||||
skipped = 0
|
||||
errors = []
|
||||
|
||||
for po in self:
|
||||
if po.sale_ord_id:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
marked_for_value = getattr(po, 'x_marked_for', None)
|
||||
if not marked_for_value:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
marked_for_str = str(marked_for_value)
|
||||
matching_partners = None
|
||||
|
||||
# Check if x_marked_for contains a partner ID reference
|
||||
partner_id_match = re.search(r'res\.partner\((\d+)', marked_for_str)
|
||||
if partner_id_match:
|
||||
partner_id = int(partner_id_match.group(1))
|
||||
matching_partners = self.env['res.partner'].browse(partner_id).exists()
|
||||
|
||||
# If not a partner ID reference, search by name
|
||||
if not matching_partners:
|
||||
matching_partners = self.env['res.partner'].search([
|
||||
'|',
|
||||
('name', 'ilike', marked_for_str),
|
||||
('display_name', 'ilike', marked_for_str)
|
||||
])
|
||||
|
||||
if not matching_partners:
|
||||
errors.append(_("PO %s: No customer found for '%s'") % (po.name, marked_for_str))
|
||||
continue
|
||||
|
||||
# Find Sale Orders for these partners
|
||||
matching_sales = self.env['sale.order'].search([
|
||||
('partner_id', 'in', matching_partners.ids)
|
||||
])
|
||||
|
||||
if not matching_sales:
|
||||
errors.append(_("PO %s: No SO found for '%s'") % (po.name, matching_partners[0].name))
|
||||
continue
|
||||
|
||||
if len(matching_sales) > 1:
|
||||
errors.append(_("PO %s: Multiple SOs (%d) for '%s'") % (po.name, len(matching_sales), matching_partners[0].name))
|
||||
continue
|
||||
|
||||
# Exactly one match - link it with actual customer name
|
||||
customer_name = matching_partners[0].name
|
||||
po.write({
|
||||
'sale_ord_id': matching_sales.id,
|
||||
'marked_for': customer_name,
|
||||
})
|
||||
matched += 1
|
||||
|
||||
message = _("Matched: %d, Skipped: %d") % (matched, skipped)
|
||||
if errors:
|
||||
message += "\n" + "\n".join(errors[:5]) # Show first 5 errors
|
||||
if len(errors) > 5:
|
||||
message += _("\n... and %d more errors") % (len(errors) - 5)
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('Batch Match Complete'),
|
||||
'message': message,
|
||||
'type': 'info' if matched > 0 else 'warning',
|
||||
'sticky': True,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user