mirror of
https://github.com/rickbarrette/redmine_qbo.git
synced 2026-04-02 08:21:57 -04:00
Refactored QBO service calls
This commit is contained in:
@@ -16,11 +16,9 @@ class QboSyncJob < ApplicationJob
|
|||||||
def perform(full_sync: false, id: nil, entity: nil, doc_number: nil)
|
def perform(full_sync: false, id: nil, entity: nil, doc_number: nil)
|
||||||
raise "An entity to sync is required" unless entity
|
raise "An entity to sync is required" unless entity
|
||||||
@entity = entity
|
@entity = entity
|
||||||
qbo = QboConnectionService.current!
|
|
||||||
raise "No QBO configuration found" unless qbo
|
|
||||||
|
|
||||||
log "Starting #{full_sync ? 'full' : 'incremental'} sync for #{entity} ##{id || doc_number || 'all'}..."
|
log "Starting #{full_sync ? 'full' : 'incremental'} sync for #{entity} ##{id || doc_number || 'all'}..."
|
||||||
service = "#{entity}SyncService".constantize.new(qbo: qbo)
|
service = "#{entity}SyncService".constantize.new
|
||||||
|
|
||||||
if id.present?
|
if id.present?
|
||||||
service.sync_by_id(id)
|
service.sync_by_id(id)
|
||||||
|
|||||||
@@ -98,15 +98,13 @@ class QboBaseModel < ActiveRecord::Base
|
|||||||
# Fetches the entity's details from QuickBooks Online.
|
# Fetches the entity's details from QuickBooks Online.
|
||||||
def fetch_details
|
def fetch_details
|
||||||
log "Fetching details for #{model_name.name} ##{id} from QBO..."
|
log "Fetching details for #{model_name.name} ##{id} from QBO..."
|
||||||
qbo = QboConnectionService.current!
|
service_class.new(local: self).pull()
|
||||||
service_class.new(qbo: qbo, local: self).pull()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Pushs the entity's details from QuickBooks Online.
|
# Pushs the entity's details from QuickBooks Online.
|
||||||
def push_to_qbo
|
def push_to_qbo
|
||||||
log "Starting push for #{model_name.name} ##{id}..."
|
log "Starting push for #{model_name.name} ##{id}..."
|
||||||
qbo = QboConnectionService.current!
|
reslut = service_class.new(local: self).push
|
||||||
reslut = service_class.new(qbo: qbo, local: self).push
|
|
||||||
Rails.cache.delete(details_cache_key)
|
Rails.cache.delete(details_cache_key)
|
||||||
return reslut
|
return reslut
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class EstimateSyncService < SyncServiceBase
|
|||||||
# sync only one estimate
|
# sync only one estimate
|
||||||
def sync_by_doc_number(number)
|
def sync_by_doc_number(number)
|
||||||
log "Syncing estimate by doc number #{number}"
|
log "Syncing estimate by doc number #{number}"
|
||||||
with_qbo_service do |service|
|
QboConnectionService.with_qbo_service(entity: @entity) do |service|
|
||||||
persist(service.find_by( :doc_number, number).first)
|
persist(service.find_by( :doc_number, number).first)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,20 +17,11 @@ class InvoicePushService
|
|||||||
# Push invoice changes to QBO if the invoice is linked to any issues with custom field changes that need to be synced
|
# Push invoice changes to QBO if the invoice is linked to any issues with custom field changes that need to be synced
|
||||||
def push
|
def push
|
||||||
return if @invoice.qbo_sync_locked?
|
return if @invoice.qbo_sync_locked?
|
||||||
|
|
||||||
log "Pushing invoice ##{@invoice.id} to QBO due to linked issue custom field changes"
|
log "Pushing invoice ##{@invoice.id} to QBO due to linked issue custom field changes"
|
||||||
|
|
||||||
@invoice.update_column(:qbo_sync_locked, true)
|
@invoice.update_column(:qbo_sync_locked, true)
|
||||||
|
remote = QboConnectionService.with_qbo_service(entity: Invoice) do |service|
|
||||||
qbo = QboConnectionService.current!
|
|
||||||
|
|
||||||
qbo.perform_authenticated_request do |access_token|
|
|
||||||
service = Quickbooks::Service::Invoice.new( company_id: qbo.realm_id, access_token: access_token)
|
|
||||||
|
|
||||||
remote = service.fetch_by_id(@invoice.id)
|
remote = service.fetch_by_id(@invoice.id)
|
||||||
|
|
||||||
# modify remote object here if needed
|
# modify remote object here if needed
|
||||||
|
|
||||||
service.update(remote)
|
service.update(remote)
|
||||||
end
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ class PdfService
|
|||||||
def initialize(entity: entity)
|
def initialize(entity: entity)
|
||||||
raise "An entity to sync is required" unless entity
|
raise "An entity to sync is required" unless entity
|
||||||
@entity = entity
|
@entity = entity
|
||||||
@qbo = QboConnectionService.current!
|
|
||||||
raise "No QBO configuration found" unless @qbo
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Fetches the PDF for the given entity IDs. If multiple IDs are provided, their PDFs are combined into a single document.
|
# Fetches the PDF for the given entity IDs. If multiple IDs are provided, their PDFs are combined into a single document.
|
||||||
|
|||||||
@@ -10,6 +10,11 @@
|
|||||||
|
|
||||||
class QboConnectionService
|
class QboConnectionService
|
||||||
|
|
||||||
|
# Returns the current QBO connection record. Raises an error if no connection exists.
|
||||||
|
def self.current!
|
||||||
|
Qbo.first || raise("QBO not connected")
|
||||||
|
end
|
||||||
|
|
||||||
# Replaces the existing QBO connection with new credentials. Deletes all existing records and creates a new one with the provided token, refresh token, and realm ID. Refreshes the token immediately after creation.
|
# Replaces the existing QBO connection with new credentials. Deletes all existing records and creates a new one with the provided token, refresh token, and realm ID. Refreshes the token immediately after creation.
|
||||||
def self.replace!(token:, refresh_token:, realm_id:)
|
def self.replace!(token:, refresh_token:, realm_id:)
|
||||||
Qbo.transaction do
|
Qbo.transaction do
|
||||||
@@ -24,9 +29,14 @@ class QboConnectionService
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the current QBO connection record. Raises an error if no connection exists.
|
# Performs authenticaed requests with QBO service
|
||||||
def self.current!
|
def self.with_qbo_service(entity: nil)
|
||||||
Qbo.first || raise("QBO not connected")
|
qbo = current!
|
||||||
|
raise "An entity to sync is required" unless entity
|
||||||
|
service_class ||= "Quickbooks::Service::#{entity}".constantize
|
||||||
|
qbo.perform_authenticated_request do |access_token|
|
||||||
|
service = service_class.new( company_id: qbo.realm_id, access_token: access_token )
|
||||||
|
yield service
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -13,11 +13,9 @@ class ServiceBase
|
|||||||
# Subclasses should Initializes the service with a QBO client and a local record.
|
# Subclasses should Initializes the service with a QBO client and a local record.
|
||||||
# The QBO client is used to communicate with QuickBooks Online, while the local record contains the data that needs to be pushed to QBO.
|
# The QBO client is used to communicate with QuickBooks Online, while the local record contains the data that needs to be pushed to QBO.
|
||||||
# If no local is provided, the service will not perform any operations.
|
# If no local is provided, the service will not perform any operations.
|
||||||
def initialize(qbo:, local: nil)
|
def initialize(local: nil)
|
||||||
@entity = local.class.name
|
@entity = local.class.name
|
||||||
raise "No QBO configuration found" unless qbo
|
|
||||||
raise "#{@entity} record is required for push operation" unless local
|
raise "#{@entity} record is required for push operation" unless local
|
||||||
@qbo = qbo
|
|
||||||
@local = local
|
@local = local
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -31,7 +29,7 @@ class ServiceBase
|
|||||||
return build_qbo_remote unless @local.present?
|
return build_qbo_remote unless @local.present?
|
||||||
return build_qbo_remote unless @local.id
|
return build_qbo_remote unless @local.id
|
||||||
log "Fetching details for #{@entity} ##{@local.id} from QBO..."
|
log "Fetching details for #{@entity} ##{@local.id} from QBO..."
|
||||||
with_qbo_service do |service|
|
QboConnectionService.with_qbo_service(entity: @entity) do |service|
|
||||||
service.fetch_by_id(@local.id)
|
service.fetch_by_id(@local.id)
|
||||||
end
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
@@ -45,7 +43,7 @@ class ServiceBase
|
|||||||
# If the push is successful, it returns the remote record; otherwise, it logs the error and returns false.
|
# If the push is successful, it returns the remote record; otherwise, it logs the error and returns false.
|
||||||
def push
|
def push
|
||||||
log "Pushing #{@entity} ##{@local.id} to QBO..."
|
log "Pushing #{@entity} ##{@local.id} to QBO..."
|
||||||
remote = with_qbo_service do |service|
|
remote = QboConnectionService.with_qbo_service(entity: @entity) do |service|
|
||||||
if @local.id.present?
|
if @local.id.present?
|
||||||
log "Updating #{@entity}"
|
log "Updating #{@entity}"
|
||||||
service.update(@local.details)
|
service.update(@local.details)
|
||||||
@@ -61,22 +59,9 @@ class ServiceBase
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Performs authenticaed requests with QBO service
|
|
||||||
def with_qbo_service
|
|
||||||
@qbo.perform_authenticated_request do |access_token|
|
|
||||||
service = service_class.new( company_id: @qbo.realm_id, access_token: access_token )
|
|
||||||
yield service
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Log messages with the entity type for better traceability
|
# Log messages with the entity type for better traceability
|
||||||
def log(msg)
|
def log(msg)
|
||||||
Rails.logger.info "[#{@entity}Service] #{msg}"
|
Rails.logger.info "[#{@entity}Service] #{msg}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Dynamically get the Quickbooks Service Class
|
|
||||||
def service_class
|
|
||||||
@service_class ||= "Quickbooks::Service::#{@entity}".constantize
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -12,9 +12,7 @@ class SyncServiceBase
|
|||||||
PAGE_SIZE = 1000
|
PAGE_SIZE = 1000
|
||||||
|
|
||||||
# Subclasses should initialize with a QBO client instance
|
# Subclasses should initialize with a QBO client instance
|
||||||
def initialize(qbo:)
|
def initialize()
|
||||||
raise "No QBO configuration found" unless qbo
|
|
||||||
@qbo = qbo
|
|
||||||
@entity = self.class.model_class
|
@entity = self.class.model_class
|
||||||
@page_size = self.class.page_size
|
@page_size = self.class.page_size
|
||||||
end
|
end
|
||||||
@@ -32,7 +30,7 @@ class SyncServiceBase
|
|||||||
# Sync all entities, or only those updated since the last sync
|
# Sync all entities, or only those updated since the last sync
|
||||||
def sync(full_sync: false)
|
def sync(full_sync: false)
|
||||||
log "Starting #{full_sync ? 'full' : 'incremental'} #{@entity.name} sync with page size of: #{@page_size}"
|
log "Starting #{full_sync ? 'full' : 'incremental'} #{@entity.name} sync with page size of: #{@page_size}"
|
||||||
with_qbo_service do |service|
|
QboConnectionService.with_qbo_service(entity: @entity) do |service|
|
||||||
query = build_query(full_sync)
|
query = build_query(full_sync)
|
||||||
service.query_in_batches(query, per_page: @page_size) do |batch|
|
service.query_in_batches(query, per_page: @page_size) do |batch|
|
||||||
entries = Array(batch)
|
entries = Array(batch)
|
||||||
@@ -49,7 +47,7 @@ class SyncServiceBase
|
|||||||
# Sync a single entity by its QBO ID (webhook usage)
|
# Sync a single entity by its QBO ID (webhook usage)
|
||||||
def sync_by_id(id)
|
def sync_by_id(id)
|
||||||
log "Syncing #{@entity.name} with ID #{id}"
|
log "Syncing #{@entity.name} with ID #{id}"
|
||||||
with_qbo_service do |service|
|
QboConnectionService.with_qbo_service(entity: @entity) do |service|
|
||||||
remote = service.fetch_by_id(id)
|
remote = service.fetch_by_id(id)
|
||||||
persist(remote)
|
persist(remote)
|
||||||
end
|
end
|
||||||
@@ -240,17 +238,4 @@ class SyncServiceBase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Dynamically get the Quickbooks Service Class
|
|
||||||
def service_class
|
|
||||||
@service_class ||= "Quickbooks::Service::#{@entity}".constantize
|
|
||||||
end
|
|
||||||
|
|
||||||
# Performs authenticaed requests with QBO service
|
|
||||||
def with_qbo_service
|
|
||||||
@qbo.perform_authenticated_request do |access_token|
|
|
||||||
service = service_class.new( company_id: @qbo.realm_id, access_token: access_token )
|
|
||||||
yield service
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
Reference in New Issue
Block a user