# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) import logging from odoo import http from odoo.http import request _logger = logging.getLogger(__name__) class WooProductSearchController(http.Controller): """AJAX search endpoints used by the product mapping UI.""" # ------------------------------------------------------------------------- # Endpoints # ------------------------------------------------------------------------- @http.route( '/woo/search/odoo_products', type='jsonrpc', auth='user', methods=['POST'], ) def search_odoo_products(self, query='', instance_id=None, limit=20, offset=0, **kw): """ Search Odoo products by name or internal reference (SKU). Params: query (str): Search string matched against name and default_code. instance_id (int): woo.instance ID (used for future per-instance filtering). limit (int): Max results to return (default 20). offset (int): Offset for pagination (default 0). Returns: dict with 'results' list and 'total' count """ limit = min(int(limit or 20), 100) offset = int(offset or 0) domain = [] if query: domain = [ '|', ('name', 'ilike', query), ('default_code', 'ilike', query), ] total = request.env['product.product'].search_count(domain) products = request.env['product.product'].search(domain, limit=limit, offset=offset) return { 'results': [ { 'id': p.id, 'name': p.name, 'default_code': p.default_code or '', 'list_price': p.list_price, 'qty_available': p.qty_available, } for p in products ], 'total': total, } @http.route( '/woo/search/woo_products', type='jsonrpc', auth='user', methods=['POST'], ) def search_woo_products(self, query='', instance_id=None, limit=20, offset=0, **kw): """ Search unmapped WooCommerce products from the woo.product.map model. Params: query (str): Search string matched against woo_product_name and woo_sku. instance_id (int): woo.instance ID — filters results to this instance. limit (int): Max results to return (default 20). offset (int): Offset for pagination (default 0). Returns: dict with 'results' list and 'total' count """ limit = min(int(limit or 20), 100) offset = int(offset or 0) domain = [('state', '=', 'unmapped')] if instance_id: domain.append(('instance_id', '=', int(instance_id))) if query: domain += [ '|', ('woo_product_name', 'ilike', query), ('woo_sku', 'ilike', query), ] total = request.env['woo.product.map'].search_count(domain) maps = request.env['woo.product.map'].search(domain, limit=limit, offset=offset) return { 'results': [ { 'id': m.id, 'woo_product_id': m.woo_product_id, 'woo_product_name': m.woo_product_name or '', 'woo_sku': m.woo_sku or '', 'woo_product_type': m.woo_product_type or '', } for m in maps ], 'total': total, } @http.route( '/woo/search/mapped', type='jsonrpc', auth='user', methods=['POST'], ) def search_mapped(self, query='', instance_id=None, limit=20, offset=0, **kw): """ Search mapped WooCommerce ↔ Odoo product pairs. Params: query (str): Matched against woo_product_name, woo_sku, and linked product name. instance_id (int): woo.instance ID — filters results to this instance. limit (int): Max results to return (default 20). offset (int): Offset for pagination (default 0). Returns: dict with 'results' list and 'total' count """ limit = min(int(limit or 20), 100) offset = int(offset or 0) domain = [('state', '=', 'mapped')] if instance_id: domain.append(('instance_id', '=', int(instance_id))) if query: domain += [ '|', '|', ('woo_product_name', 'ilike', query), ('woo_sku', 'ilike', query), ('product_id.name', 'ilike', query), ] total = request.env['woo.product.map'].search_count(domain) maps = request.env['woo.product.map'].search(domain, limit=limit, offset=offset) return { 'results': [ { 'id': m.id, 'woo_product_id': m.woo_product_id, 'woo_product_name': m.woo_product_name or '', 'woo_sku': m.woo_sku or '', 'woo_product_type': m.woo_product_type or '', 'woo_permalink': m.woo_permalink or '', 'odoo_product_id': m.product_id.id if m.product_id else False, 'odoo_product_name': m.product_id.name if m.product_id else '', 'odoo_default_code': m.product_id.default_code or '' if m.product_id else '', 'odoo_price': m.product_id.list_price if m.product_id else 0.0, 'odoo_cost': m.product_id.standard_price if m.product_id else 0.0, 'woo_regular_price': m.woo_regular_price or 0.0, 'woo_sale_price': m.woo_sale_price or 0.0, 'sync_price': m.sync_price, 'sync_inventory': m.sync_inventory, 'instance_id': m.instance_id.id if m.instance_id else False, 'instance_name': m.instance_id.name if m.instance_id else '', } for m in maps ], 'total': total, }