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>
84 lines
2.1 KiB
Ruby
84 lines
2.1 KiB
Ruby
# 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
|