diff --git a/app/controllers/invoice_controller.rb b/app/controllers/invoice_controller.rb index f0a7a58..6bf1e4b 100644 --- a/app/controllers/invoice_controller.rb +++ b/app/controllers/invoice_controller.rb @@ -1,6 +1,6 @@ #The MIT License (MIT) # -#Copyright (c) 2022 rick barrette +#Copyright (c) 2023 rick barrette # #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: # @@ -20,9 +20,15 @@ class InvoiceController < ApplicationController # def show begin - base = Invoice.get_base - invoice = base.fetch_by_id(params[:id]) - @pdf = base.pdf(invoice) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Invoice.new(:company_id => qbo.realm_id, :access_token => access_token) + invoice = service.fetch_by_id(params[:id]) + @pdf = service.pdf(invoice) + end + + return unless @pdf + send_data @pdf, filename: "invoice #{invoice.doc_number}.pdf", :disposition => 'inline', :type => "application/pdf" rescue redirect_to :back, :flash => { :error => "Invoice not found" } diff --git a/app/models/customer.rb b/app/models/customer.rb index 1314de8..04dc6fe 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -1,6 +1,6 @@ #The MIT License (MIT) # -#Copyright (c) 2022 rick barrette +#Copyright (c) 2023 rick barrette # #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: # @@ -142,17 +142,14 @@ class Customer < ActiveRecord::Base # proforms a bruteforce sync operation # This needs to be simplified def self.sync - service = Qbo.get_base(:customer) - # Sync ALL customers if the database is empty - #if count == 0 + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Customer.new(:company_id => qbo.realm_id, :access_token => access_token) customers = service.all - #else - # last = Qbo.first.last_sync - # query = "Select Id, DisplayName From Customer" - # query << " Where Metadata.LastUpdatedTime >= '#{last.iso8601}' " if last - # customers = service.query(query) - #end + end + + return unless customers customers.each do |c| logger.info "Processing customer #{c.id}" @@ -180,9 +177,14 @@ class Customer < ActiveRecord::Base # proforms a bruteforce sync operation # This needs to be simplified def self.sync_by_id(id) - service = Qbo.get_base(:customer) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Customer.new(:company_id => qbo.realm_id, :access_token => access_token) + customer = service.fetch_by_id(id) + end + + return unless customer - customer = service.fetch_by_id(id) customer = Customer.find_or_create_by(id: customer.id) if customer.active? if not customer.name.eql? customer.display_name @@ -200,7 +202,11 @@ class Customer < ActiveRecord::Base # Push the updates def save_with_push begin - @details = Qbo.get_base(:customer).update(@details) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Customer.new(:company_id => qbo.realm_id, :access_token => access_token) + @details = serivce.update(@details) + end #raise "QBO Fault" if @details.fault? self.id = @details.id rescue Exception => e @@ -218,7 +224,11 @@ class Customer < ActiveRecord::Base def pull begin raise Exception unless self.id - @details = Qbo.get_base(:customer).fetch_by_id(self.id) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Customer.new(:company_id => qbo.realm_id, :access_token => access_token) + @details = bservice.ase.fetch_by_id(self.id) + end rescue Exception => e @details = Quickbooks::Model::Customer.new end diff --git a/app/models/employee.rb b/app/models/employee.rb index 3319558..54c23ea 100644 --- a/app/models/employee.rb +++ b/app/models/employee.rb @@ -13,12 +13,14 @@ class Employee < ActiveRecord::Base has_many :users validates_presence_of :id, :name - def self.get_base - Qbo.get_base(:employee) - end - def self.sync - employees = get_base.all + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Employee.new(:company_id => qbo.realm_id, :access_token => access_token) + employees = service.all + end + + return unless employees transaction do # Update the item table @@ -33,7 +35,13 @@ class Employee < ActiveRecord::Base end def self.sync_by_id(id) - employee = get_base.fetch_by_id(id) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Employee.new(:company_id => qbo.realm_id, :access_token => access_token) + employee = service.fetch_by_id(id) + end + + return unless employee employee = find_or_create_by(id: employee.id) employee.name = employee.display_name employee.id = employee.id diff --git a/app/models/estimate.rb b/app/models/estimate.rb index 541f4bd..641ff39 100644 --- a/app/models/estimate.rb +++ b/app/models/estimate.rb @@ -1,6 +1,6 @@ #The MIT License (MIT) # -#Copyright (c) 2022 rick barrette +#Copyright (c) 2023 rick barrette # #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: # @@ -16,15 +16,17 @@ class Estimate < ActiveRecord::Base validates_presence_of :doc_number, :id self.primary_key = :id - # return the QBO Estimate service - def self.get_base - Qbo.get_base(:estimate) - end - # sync all estimates def self.sync logger.debug "Syncing ALL estimates" - estimates = get_base.all + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Estimate.new(:company_id => qbo.realm_id, :access_token => access_token) + estimates = service.all + end + + return unless estimates + estimates.each { |estimate| process_estimate(estimate) } @@ -36,17 +38,28 @@ class Estimate < ActiveRecord::Base # sync only one estimate def self.sync_by_id(id) logger.debug "Syncing estimate #{id}" - process_estimate(get_base.fetch_by_id(id)) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Estimate.new(:company_id => qbo.realm_id, :access_token => access_token) + process_estimate(service.fetch_by_id(id)) + end end # update an estimate def self.update(id) # Update the item table - estimate = get_base.fetch_by_id(id) - estimate = find_or_create_by(id: id) - estimate.doc_number = estimate.doc_number - estimate.txn_date = estimate.txn_date - estimate.save! + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Estimate.new(:company_id => qbo.realm_id, :access_token => access_token) + estimate = service.fetch_by_id(id) + end + + return unless estimate + + e = find_or_create_by(id: id) + e.doc_number = estimate.doc_number + e.txn_date = estimate.txn_date + e.save! end # process an estimate into the database @@ -62,9 +75,12 @@ class Estimate < ActiveRecord::Base # download the pdf from quickbooks def pdf - base = Estimate.get_base - estimate = base.fetch_by_id(id) - return base.pdf(estimate) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Estimate.new(:company_id => qbo.realm_id, :access_token => access_token) + estimate = service.fetch_by_id(id) + return service.pdf(estimate) + end end # Magic Method @@ -91,7 +107,11 @@ class Estimate < ActiveRecord::Base def pull begin raise Exception unless self.id - @details = Qbo.get_base(:estimate).fetch_by_id(self.id) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Estimate.new(:company_id => qbo.realm_id, :access_token => access_token) + @details = service(:estimate).fetch_by_id(self.id) + end rescue Exception => e @details = Quickbooks::Model::Estimate.new end diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 8644e72..4b6d570 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -1,6 +1,6 @@ #The MIT License (MIT) # -#Copyright (c) 2022 rick barrette +#Copyright (c) 2023 rick barrette # #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: # @@ -15,11 +15,6 @@ class Invoice < ActiveRecord::Base validates_presence_of :doc_number, :id, :customer_id, :txn_date self.primary_key = :id - # Get the quickbooks-ruby base for invoice - def self.get_base - Qbo.get_base(:invoice) - end - # sync ALL the invoices def self.sync logger.debug "Syncing all invoices" @@ -30,11 +25,17 @@ class Invoice < ActiveRecord::Base # TODO actually do something with the above query # .all() is never called since count is never initialized - if count == 0 - invoices = get_base.all - else - invoices = get_base.query() + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Invoice.new(:company_id => qbo.realm_id, :access_token => access_token) + if count == 0 + invoices = service.all + else + invoices = service.query() + end end + + return unless invoices invoices.each { | invoice | process_invoice invoice @@ -44,8 +45,12 @@ class Invoice < ActiveRecord::Base #sync by invoice ID def self.sync_by_id(id) logger.debug "Syncing invoice #{id}" - invoice = get_base.fetch_by_id(id) - process_invoice invoice + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Invoice.new(:company_id => qbo.realm_id, :access_token => access_token) + invoice = service.fetch_by_id(id) + process_invoice invoice + end end private @@ -155,7 +160,11 @@ class Invoice < ActiveRecord::Base # Push updates begin logger.debug "Trying to update invoice" - get_base.update(invoice) if is_changed + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Invoice.new(:company_id => qbo.realm_id, :access_token => access_token) + service.update(invoice) if is_changed + end rescue # Do nothing, probaly custome field sync confict on the invoice. # This is a problem with how it's billed @@ -187,7 +196,11 @@ class Invoice < ActiveRecord::Base def pull begin raise Exception unless self.id - @details = Qbo.get_base(:invoice).fetch_by_id(self.id) + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Invoice.new(:company_id => qbo.realm_id, :access_token => access_token) + @details = service.fetch_by_id(self.id) + end rescue Exception => e @details = Quickbooks::Model::Invoice.new end diff --git a/app/models/qbo.rb b/app/models/qbo.rb index 66c9984..06199b7 100644 --- a/app/models/qbo.rb +++ b/app/models/qbo.rb @@ -1,6 +1,6 @@ #The MIT License (MIT) # -#Copyright (c) 2022 rick barrette +#Copyright (c) 2023 rick barrette # #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: # @@ -12,34 +12,6 @@ class Qbo < ActiveRecord::Base unloadable include QuickbooksOauth - - # - # Get a quickbooks base service object for type - # @params type of base - # - def self.get_base(type) - qbo = self.first - - qbo.perform_authenticated_request do |access_token| - # build the reqiested service - case type - when :time_activity - return Quickbooks::Service::TimeActivity.new(:company_id => qbo.realm_id, :access_token => access_token) - when :customer - return Quickbooks::Service::Customer.new(:company_id => qbo.realm_id, :access_token => access_token) - when :invoice - return Quickbooks::Service::Invoice.new(:company_id => qbo.realm_id, :access_token => access_token) - when :estimate - return Quickbooks::Service::Estimate.new(:company_id => qbo.realm_id, :access_token => access_token) - when :employee - return Quickbooks::Service::Employee.new(:company_id => qbo.realm_id, :access_token => access_token) - when :item - return Quickbooks::Service::Item.new(:company_id => qbo.realm_id, :access_token => access_token) - else - return nil - end - end - end # Updates last sync time stamp def self.update_time_stamp diff --git a/db/migrate/032_add_txn_dates.rb b/db/migrate/032_add_txn_dates.rb index c6915c3..5e1a68d 100644 --- a/db/migrate/032_add_txn_dates.rb +++ b/db/migrate/032_add_txn_dates.rb @@ -1,6 +1,6 @@ #The MIT License (MIT) # -#Copyright (c) 2022 rick barrette +#Copyright (c) 2023 rick barrette # #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: # @@ -26,7 +26,13 @@ class AddTxnDates < ActiveRecord::Migration[5.1] say "Sync Invoices" - invoices = QboInvoice.get_base.all + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + service = Quickbooks::Service::Invoice.new(:company_id => qbo.realm_id, :access_token => access_token) + invoices = service.all + end + + return unless invoices invoices.each { |invoice| # Load the invoice into the database diff --git a/lib/issue_patch.rb b/lib/issue_patch.rb index b7c1ecd..a804bff 100644 --- a/lib/issue_patch.rb +++ b/lib/issue_patch.rb @@ -1,6 +1,6 @@ #The MIT License (MIT) # -#Copyright (c) 2022 rick barrette +#Copyright (c) 2023 rick barrette # #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: # @@ -52,46 +52,49 @@ module IssuePatch if spent_hours > 0 then # Prepare to create a new Time Activity - time_service = Qbo.get_base(:time_activity) - item_service = Qbo.get_base(:item) - time_entry = Quickbooks::Model::TimeActivity.new + qbo = Qbo.first + qbo.perform_authenticated_request do |access_token| + time_service = Quickbooks::Service::TimeActivity.new(:company_id => qbo.realm_id, :access_token => access_token) + item_service = Quickbooks::Service::Item.new(:company_id => qbo.realm_id, :access_token => access_token) + time_entry = Quickbooks::Model::TimeActivity.new - # Lets total up each activity before billing. - # This will simpify the invoicing with a single billable time entry per time activity - h = Hash.new(0) - spent_time.each do |entry| - h[entry.activity.name] += entry.hours - # update time entries billed status - entry.billed = true - entry.save - end - - # Now letes upload our totals for each activity as their own billable time entry - h.each do |key, val| + # Lets total up each activity before billing. + # This will simpify the invoicing with a single billable time entry per time activity + h = Hash.new(0) + spent_time.each do |entry| + h[entry.activity.name] += entry.hours + # update time entries billed status + entry.billed = true + entry.save + end - # Convert float spent time to hours and minutes - hours = val.to_i - minutesDecimal = (( val - hours) * 60) - minutes = minutesDecimal.to_i + # Now letes upload our totals for each activity as their own billable time entry + h.each do |key, val| + + # Convert float spent time to hours and minutes + hours = val.to_i + minutesDecimal = (( val - hours) * 60) + minutes = minutesDecimal.to_i - # Lets match the activity to an qbo item - item = item_service.query("SELECT * FROM Item WHERE Name = '#{key}' ").first - next if item.nil? - - # Create the new billable time entry and upload it - time_entry.description = "#{tracker} ##{id}: #{subject} #{"(Partial @ #{done_ratio}%)" if not closed?}" - time_entry.employee_id = assigned_to.employee_id - time_entry.customer_id = customer_id - time_entry.billable_status = "Billable" - time_entry.hours = hours - time_entry.minutes = minutes - time_entry.name_of = "Employee" - time_entry.txn_date = Date.today - time_entry.hourly_rate = item.unit_price - time_entry.item_id = item.id - time_entry.start_time = start_date - time_entry.end_time = Time.now - time_service.create(time_entry) + # Lets match the activity to an qbo item + item = item_service.query("SELECT * FROM Item WHERE Name = '#{key}' ").first + next if item.nil? + + # Create the new billable time entry and upload it + time_entry.description = "#{tracker} ##{id}: #{subject} #{"(Partial @ #{done_ratio}%)" if not closed?}" + time_entry.employee_id = assigned_to.employee_id + time_entry.customer_id = customer_id + time_entry.billable_status = "Billable" + time_entry.hours = hours + time_entry.minutes = minutes + time_entry.name_of = "Employee" + time_entry.txn_date = Date.today + time_entry.hourly_rate = item.unit_price + time_entry.item_id = item.id + time_entry.start_time = start_date + time_entry.end_time = Time.now + time_service.create(time_entry) + end end end end