diff --git a/app/channels/api_channel.rb b/app/channels/api_channel.rb
index 697eb78c..0ba31118 100644
--- a/app/channels/api_channel.rb
+++ b/app/channels/api_channel.rb
@@ -141,18 +141,34 @@ def zero_results data
     end
   end
 
-  def finish data
+  def zero_no_solution data
     return unless scoring_open data
 
     task = Task.find task_id
+    force_close_and_finish! task
+    dispatch_self 'notifications/push', kind: 'info', message: 'Zeroing results for users without solutions …'
 
-    task.update_column :scoring_open, false
-    RedisLockManager.release_all
-    dispatch_all 'locks/load', RedisLockManager.all
-    dispatch_all 'results/load', CriterionUserResult.includes(:user).where(criterion: task_criterions)
-    dispatch_all 'comments/load', Comment.includes(:user).where(task_id:)
-    dispatch_all 'app/finish'
+    users_without_any_solution = Set.new task_users.where.missing(:solutions).pluck(:id)
+    begin
+      ActiveRecord::Base.transaction do
+        task.contest.users.find_each do |user|
+          next if user.solutions.exists?(task_id:)
+
+          task.criterions.each { CriterionUserResult.create_or_find_by!(user:, criterion: _1).update!(value: 0) }
+          comment = users_without_any_solution.include?(user.id) ? 'папка відсутня' : 'файл відсутній'
+          Comment.create_or_find_by!(user:, task_id:).update!(value: comment)
+        end
+      end
+    ensure
+      reopen! task
+    end
+  end
 
+  def finish data
+    return unless scoring_open data
+
+    task = Task.find task_id
+    force_close_and_finish! task
     dispatch_self 'notifications/push', kind: 'info', message: 'Calculating results …'
 
     users_without_result = []
@@ -170,8 +186,7 @@ def finish data
         raise "Users that missing some result: #{users_without_result.to_sentence}" unless users_without_result.empty?
       end
     rescue StandardError => e
-      task.update_column :scoring_open, true
-      dispatch_self 'app/ready', ready_info
+      reopen! task
       raise e
     else
       dispatch_self 'notifications/push', kind: 'success', message: 'Results calculated'
@@ -223,4 +238,20 @@ def scoring_open data
     dispatch_self 'errors/push', "#{data['action']} failed: Scoring is closed"
     false
   end
+
+  def force_close_and_finish! task
+    task.update_column :scoring_open, false
+    RedisLockManager.release_all
+    dispatch_all 'locks/load', RedisLockManager.all
+    dispatch_all 'results/load', CriterionUserResult.includes(:user).where(criterion: task_criterions)
+    dispatch_all 'comments/load', Comment.includes(:user).where(task_id:)
+    dispatch_all 'app/finish'
+  end
+
+  def reopen! task
+    task.update_column :scoring_open, true
+    dispatch_all 'results/load', CriterionUserResult.includes(:user).where(criterion: task_criterions)
+    dispatch_all 'comments/load', Comment.includes(:user).where(task_id:)
+    dispatch_all 'app/ready', ready_info
+  end
 end