When you build a query like the one you attempt the query optimizer will have to create one plan to fit any value of the parameters. This will result in the worst possible plan. So even if you come up with the right expression (using CASE), the query will be very badly performing due to the contradicting OR conditions.
Separate the IFs into SQL conditions and use distinct queries for each case:
IF @booked_in IS NULL and @depot_assigned IS NULL
SELECT * FROM sales_order_header
WHERE order_reference LIKE @order_reference + '%'
ELSE IF @depot_assigned IS NULL
SELECT * FROM sales_order_header
WHERE order_reference LIKE @order_reference + '%'
AND booked_in = @booked_in
ELSE IF @booked_in IS NULL AND @depot_code='Y'
SELECT * FROM sales_order_header
WHERE order_reference LIKE @order_reference + '%'
AND depot_code <> ' '
ELSE IF IF @booked_in IS NULL AND @depot_code<>'Y'
SELECT * FROM sales_order_header
WHERE order_reference LIKE @order_reference + '%'
AND depot_code = ' '
ELSE IF @depot_code = 'Y'
SELECT * FROM sales_order_header
WHERE order_reference LIKE @order_reference + '%'
AND booked_in = @booked_in
AND depot_code <> ' '
ELSE
SELECT * FROM sales_order_header
WHERE order_reference LIKE @order_reference + '%'
AND booked_in = @booked_in
AND depot_code = ' '
Despite the apparent ungliness and lack of elegance, this is the best approach. Its main draw back is maintenability problems, and to cure that there is a viable alternative in the use dynamic SQL to build the query.
Ultimately, the complexity of the IF conditions are a code smell that your data access API does too many things that should be separate API entry points.