Initial commit

This commit is contained in:
gsinghpal
2026-02-22 01:22:18 -05:00
commit 5200d5baf0
2394 changed files with 386834 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import sale_order_to_purchase_order_app

View File

@@ -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,
}
}