Help for odoo.find_quotes

odoo ยท find_quotes

Sample CLI

gway odoo find-quotes

References

Full Code

def find_quotes(
    *,
    product,
    quantity: int = 1,
    state: str = 'draft',
    **kwargs
):
    """
    Find all sale quotes that contain a given product (by id or name substring) with at least the given quantity.

    Parameters:
        product (str or int): Product ID or partial name.
        quantity (int): Minimum quantity of the product in the quote. Default is 1.
        state (str): Odoo sale order state (default: 'draft' for quotations).
        **kwargs: Additional domain filters for sale.order.

    Returns:
        list: List of matching sale orders (quotes) with product line details.
    """
    gw.info(f"Finding quotes for {product=} {quantity=}")
    # Step 1: Resolve product id if necessary
    product_id = None

    # Try converting product to integer (for id)
    try:
        product_id = int(product)
        product_name = None
    except (ValueError, TypeError):
        # Search by product name substring
        results = fetch_products(name=product)
        if not results:
            return {"error": f"No products found matching: {product}"}
        if len(results) > 1:
            return {
                "error": f"Ambiguous product name '{product}', matches: " +
                         ", ".join([f"{p['id']}: {p['name']}" for p in results])
            }
        product_id = results[0]['id']
        product_name = results[0]['name']
        gw.info(f"Resolved product '{product}' to id {product_id} ('{product_name}')")
    
    # Step 2: Find sale order lines matching product + min quantity
    line_model = 'sale.order.line'
    line_method = 'search_read'
    domain_lines = [
        ('product_id', '=', product_id),
        ('product_uom_qty', '>=', quantity)
    ]
    line_fields = ['order_id', 'product_id', 'product_uom_qty', 'name']
    sale_lines = execute_kw(
        [domain_lines],
        {'fields': line_fields},
        model=line_model,
        method=line_method
    )
    if not sale_lines:
        return {"result": [], "info": f"No quotes found with product {product_id} and quantity >= {quantity}"}
    
    # Step 3: Collect all order_ids found in lines
    order_ids = list(set(l['order_id'][0] if isinstance(l['order_id'], (list, tuple)) else l['order_id'] for l in sale_lines))
    if not order_ids:
        return {"result": [], "info": f"No matching quotes found."}
    
    # Step 4: Fetch quotes for those order_ids with optional state filter
    order_model = 'sale.order'
    order_method = 'search_read'
    domain_orders = [('id', 'in', order_ids)]
    if state:
        domain_orders.append(('state', '=', state))
    # Add any extra filters from kwargs
    for key, value in kwargs.items():
        domain_orders.append((key, '=', value))
    fields_to_fetch = ['name', 'amount_total', 'create_date', 'user_id', 'partner_id', 'state']

    quotes = execute_kw(
        [domain_orders],
        {'fields': fields_to_fetch},
        model=order_model,
        method=order_method
    )

    # Step 5: Attach relevant line(s) for each quote
    quote_lines_by_order = {}
    for line in sale_lines:
        oid = line['order_id'][0] if isinstance(line['order_id'], (list, tuple)) else line['order_id']
        quote_lines_by_order.setdefault(oid, []).append({
            "product_id": line['product_id'],
            "qty": line['product_uom_qty'],
            "line_name": line['name'],
        })
    # Attach to each quote
    for quote in quotes:
        quote['matching_lines'] = quote_lines_by_order.get(quote['id'], [])

    return quotes