Add method to create issues from labor lines in QBO estimates

This commit is contained in:
ricky committed 2026-08-09 20:46:19 -04:00
1 parent 11bc1f1d57
commit 45fcdeebd7
1 file changed
+78 -1
+78 -1
View File
@@ -28,6 +28,65 @@ class CustomerAppointment < ActiveRecord::Base
Cancelled Cancelled
] ]
# Scans the QBO Estimate's InvoiceLineItems for "Labor" sales items
# and generates a Redmine Issue for each matching line.
#
# @param project [Project] Target project (defaults to appointment's project)
# @param author [User] Author for the new issues
# @param tracker [Tracker] Target tracker (defaults to project's first tracker)
# @return [Array<Issue>] Created issues
def create_issues_from_labor_lines(project: self.project, author: User.current, tracker: nil)
return [] if estimate.blank?
target_project = project || self.project || Project.first
target_tracker = tracker || target_project&.trackers&.first
return [] unless target_project && target_tracker
created_issues = []
# estimate.line_items returns array of Quickbooks::Model::InvoiceLineItem
estimate.line_items.each do |line|
detail = line.respond_to?(:sales_line_item_detail) ? line.sales_line_item_detail : nil
next if detail.nil? || detail.item_ref.nil?
item_name = detail.item_ref.name.to_s.strip
description = line.description.to_s.strip
# Match "Labor" (case-insensitive) and ensure description is present
next unless item_name.casecmp('Labor').zero?
next if description.blank?
# detail.quantity contains line quantity/hours; line.amount is total line cost fallback
qty = detail.respond_to?(:quantity) ? detail.quantity.to_f : 0.0
hours = qty.positive? ? qty : line.amount.to_f
issue = Issue.new(
project: target_project,
tracker: target_tracker,
assigned_to_id: self.user&.id,
author: author,
subject: description.truncate(255),
description: "The purpose of this work is to bill the time spent on this issue for Estimate ##{estimate.doc_number} for Appointment: #{subject}",
estimated_hours: hours,
start_date: self.start_date,
due_date: self.due_date,
vehicle: self.vehicle,
estimate: self.estimate,
customer: self.customer,
created_on: Time.current,
updated_on: Time.current
)
if issue.save
created_issues << issue
else
log "Failed to create issue for Estimate ##{estimate.id}: #{issue.errors.full_messages.join(', ')}"
end
end
created_issues
end
# Cast datetime to Date for Redmine Calendar compatibility # Cast datetime to Date for Redmine Calendar compatibility
def start_date def start_date
date&.to_date date&.to_date
@@ -50,7 +109,25 @@ class CustomerAppointment < ActiveRecord::Base
private private
def log(msg) def log(msg)
Rails.logger.info "[Event] #{msg}" Rails.logger.info "[CustomerAppointment] #{msg}"
end
# Helper to parse item name across Quickbooks::Model::Line and Hash structures
def extract_item_name(line)
if line.respond_to?(:sales_line_item_detail) && line.sales_line_item_detail.present?
line.sales_line_item_detail.item_ref&.name
elsif line.is_a?(Hash)
line[:item_name] || line.dig('sales_line_item_detail', 'item_ref', 'name')
end
end
# Helper to parse description across Quickbooks::Model::Line and Hash structures
def extract_description(line)
if line.respond_to?(:description)
line.description
elsif line.is_a?(Hash)
line[:description] || line['description']
end
end end
end end