Initial implementation of the reconciliation script
Standalone Ruby script reconciling GoCardless payments, Dolibarr invoices (via API), and Shine bank statements. Three-pass engine: GC↔Dolibarr matching, open invoice audit, payout↔bank verification. Includes dry-run and --fix mode to auto-mark Dolibarr invoices as paid. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
83
lib/dolibarr/client.rb
Normal file
83
lib/dolibarr/client.rb
Normal file
@@ -0,0 +1,83 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "httparty"
|
||||
require "json"
|
||||
|
||||
module Dolibarr
|
||||
class Client
|
||||
include HTTParty
|
||||
|
||||
class NotFoundError < StandardError; end
|
||||
class ValidationError < StandardError; end
|
||||
class Error < StandardError; end
|
||||
|
||||
def initialize(
|
||||
base_url: ENV.fetch("DOLIBARR_URL"),
|
||||
api_key: ENV.fetch("DOLIBARR_API_KEY")
|
||||
)
|
||||
@base_url = base_url
|
||||
@headers = {
|
||||
"DOLAPIKEY" => api_key,
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json"
|
||||
}
|
||||
end
|
||||
|
||||
def get(path, params = {})
|
||||
perform_request(:get, path, params)
|
||||
end
|
||||
|
||||
def post(path, data = {})
|
||||
perform_request(:post, path, data)
|
||||
end
|
||||
|
||||
def put(path, data = {})
|
||||
perform_request(:put, path, data)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def perform_request(method, path, data = {})
|
||||
url = "#{@base_url}#{path}"
|
||||
opts = { headers: @headers }
|
||||
|
||||
case method
|
||||
when :get
|
||||
opts[:query] = data unless data.empty?
|
||||
response = self.class.get(url, opts)
|
||||
when :post
|
||||
opts[:body] = data.to_json
|
||||
response = self.class.post(url, opts)
|
||||
when :put
|
||||
opts[:body] = data.to_json
|
||||
response = self.class.put(url, opts)
|
||||
end
|
||||
|
||||
handle_response(response)
|
||||
rescue => e
|
||||
raise Error, "Connection error: #{e.message}"
|
||||
end
|
||||
|
||||
def handle_response(response)
|
||||
return nil if response.body.nil? || response.body.strip.empty?
|
||||
|
||||
code = response.code.to_i
|
||||
case code
|
||||
when 200..299
|
||||
response.parsed_response
|
||||
when 404
|
||||
raise NotFoundError, "Not found (404)"
|
||||
when 400
|
||||
raise ValidationError, "Validation error: #{response.body}"
|
||||
when 401
|
||||
raise Error, "Authentication failed (401) — check DOLIBARR_API_KEY"
|
||||
when 500..599
|
||||
raise Error, "Dolibarr server error (#{code}): #{response.body}"
|
||||
else
|
||||
raise Error, "Unexpected status #{code}: #{response.body}"
|
||||
end
|
||||
rescue JSON::ParserError => e
|
||||
raise Error, "JSON parse error: #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user