Conditional WHERE in plpgsql function
@Ypercube's comment basically answers your core question.

But your function is also much slower and more complicated than necessary:

CREATE OR REPLACE FUNCTION find_days_business(_reception_duration int
                                            , _department_id bigint
                                            , _service_id bigint)
  RETURNS TABLE (avail_records numeric
               , busy_records bigint
               , percentage numeric
               , day_date date) AS
$func$
BEGIN
 RETURN QUERY
 SELECT s.sum_diff, n.ct, ((n.ct * 100) / s.sum_diff ), s.date
 FROM  (
    SELECT p.date, sum(p.diff) AS sum_diff
    FROM  (
       SELECT w.date
            , ceil(((max(w.time_to) - min(w.time_from)) * 60) / _reception_duration) AS diff
       FROM   workingtimetable w
       WHERE  w.date &gt;= now()::date
       AND    w.department_id = _department_id
       -- another restriction IF _service_id is not null:
       AND   (_service_id IS NULL OR &lt;another restriction&gt;)
       GROUP  BY w.user_id, w.date
       ) p          -- perday
    GROUP  BY p.date
 ) s                -- sum_of_avail_records
 LEFT   JOIN (
    SELECT d.date, count(*) AS ct
    FROM   appointments_book_records r
    JOIN   appointments_book_days    d ON r.appointment_day_id = d.id
    WHERE  d.date &gt;= now()::date
    GROUP  BY d.date
 ) n USING (date)   -- num_of_busy_records 
 ORDER  BY s.date;
END
$func$  LANGUAGE plpgsql;


Major points


Temporary tables are more expensive and not necessary here. Simple subqueries do the job.
Don't include columns in the SELECT list that you don't need for anything. Dead weight. (You also don't need to include GROUP BY expressions in the SELECT list.)
Don't ORDER BY in subqueries. While Postgres typically keeps the order in the outer SELECT for simple queries, this is completely arbitrary and not reliable. There is no provision in the SQL standard that would require propagation of ORDER BY in subqueries to the outer query.


If your are looking for fully dynamic query predicates or arbitrary dynamic query elements with optimized query plans, you'll have to use dynamic SQL and EXECUTE:


PostgresSQL dynamic execute with argument values in array
Robust approach for building SQL queries programmatically