class LinkCheckerApiReport::CreateFromBatchReport
  def initialize(payload, reportable)
    @payload = payload
    @reportable = reportable
  end

  def create
    ActiveRecord::Base.transaction do
      report = replace_or_create_report
      create_links(report)
      report
    end
  end

private

  attr_reader :payload, :reportable

  def replace_or_create_report
    begin
      replace_report
    rescue ActiveRecord::RecordNotFound
      create_report
    end
  end

  def replace_report
    report = LinkCheckerApiReport.find_by!(batch_id: batch_id)
    report.links.delete_all
    report.update!(link_report_attributes)
    report
  end

  def create_report
    LinkCheckerApiReport.create!(
      batch_id: batch_id,
      **link_report_attributes,
    )
  end

  def create_links(report)
    payload.fetch("links", []).each_with_index do |link_payload, index|
      report.links.create!(
        link_attributes_from_report(link_payload, index)
      )
    end
  end

  def link_attributes_from_report(payload, index)
    LinkCheckerApiReport::Link
      .attributes_from_link_report(payload)
      .merge(ordering: index)
  end

  def link_report_attributes
    {
      completed_at: payload.fetch("completed_at"),
      link_reportable: reportable,
      status: payload.fetch("status"),
    }
  end

  def batch_id
    payload.fetch("id")
  end
end

class LinkCheckerApiReport::CreateFromBatchReport
  def initialize(payload, reportable)
    @payload = payload
    @reportable = reportable
  end

  def create
    ActiveRecord::Base.transaction do
      report = create_report
      create_links(report)
      report
    end
  end

private

  attr_reader :payload, :reportable

  def create_report
    LinkCheckerApiReport.create!(
      batch_id: payload.fetch("id"),
      completed_at: payload.fetch("completed_at"),
      link_reportable: reportable,
      status: payload.fetch("status"),
    )
  end

  def create_links(report)
    payload.fetch("links", []).each_with_index do |link_payload, index|
      report.links.create!(
        link_attributes_from_report(link_payload, index)
      )
    end
  end

  def link_attributes_from_report(payload, index)
    LinkCheckerApiReport::Link
      .attributes_from_link_report(payload)
      .merge(ordering: index)
  end
end

--- 
+++ 
@@ -6,7 +6,7 @@
 
   def create
     ActiveRecord::Base.transaction do
-      report = create_report
+      report = replace_or_create_report
       create_links(report)
       report
     end
@@ -16,12 +16,25 @@
 
   attr_reader :payload, :reportable
 
+  def replace_or_create_report
+    begin
+      replace_report
+    rescue ActiveRecord::RecordNotFound
+      create_report
+    end
+  end
+
+  def replace_report
+    report = LinkCheckerApiReport.find_by!(batch_id: batch_id)
+    report.links.delete_all
+    report.update!(link_report_attributes)
+    report
+  end
+
   def create_report
     LinkCheckerApiReport.create!(
-      batch_id: payload.fetch("id"),
-      completed_at: payload.fetch("completed_at"),
-      link_reportable: reportable,
-      status: payload.fetch("status"),
+      batch_id: batch_id,
+      **link_report_attributes,
     )
   end
 
@@ -38,4 +51,16 @@
       .attributes_from_link_report(payload)
       .merge(ordering: index)
   end
+
+  def link_report_attributes
+    {
+      completed_at: payload.fetch("completed_at"),
+      link_reportable: reportable,
+      status: payload.fetch("status"),
+    }
+  end
+
+  def batch_id
+    payload.fetch("id")
+  end
 end
Replace or create link reports

We're coming across a problem whereby the data sync is causing
a mismatch in the batch IDs stored in Whitehall and the batch IDs
stored in the Link Checker API. This is because the databases
don't get copied across at the same time.

We thought the best solution to this would be to simply replace
any existing link report that exists with the same batch ID.
