decidim-odoo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +169 -0
  4. data/Rakefile +43 -0
  5. data/app/commands/decidim/odoo/sync_user.rb +57 -0
  6. data/app/controllers/concerns/decidim/odoo/admin/members/filterable.rb +33 -0
  7. data/app/controllers/decidim/odoo/admin/members_controller.rb +33 -0
  8. data/app/forms/decidim/odoo/verifications/odoo_member.rb +53 -0
  9. data/app/helpers/decidim/odoo/admin/odoo_helper.rb +21 -0
  10. data/app/jobs/decidim/odoo/auto_verification_job.rb +46 -0
  11. data/app/jobs/decidim/odoo/omniauth_user_sync_job.rb +24 -0
  12. data/app/jobs/decidim/odoo/sync_users_job.rb +19 -0
  13. data/app/models/concerns/decidim/odoo/user_override.rb +21 -0
  14. data/app/models/decidim/odoo/user.rb +18 -0
  15. data/app/packs/entrypoints/decidim_odoo.js +2 -0
  16. data/app/packs/images/odoo_logo.svg +4 -0
  17. data/app/views/decidim/odoo/admin/members/index.html.erb +58 -0
  18. data/config/assets.rb +8 -0
  19. data/config/i18n-tasks.yml +8 -0
  20. data/config/locales/en.yml +41 -0
  21. data/db/migrate/20230713143501_create_decidim_odoo_users.rb +20 -0
  22. data/lib/decidim/odoo/admin.rb +10 -0
  23. data/lib/decidim/odoo/admin_engine.rb +49 -0
  24. data/lib/decidim/odoo/api/base/base_query.rb +28 -0
  25. data/lib/decidim/odoo/api/base/request.rb +48 -0
  26. data/lib/decidim/odoo/api/find_partner.rb +21 -0
  27. data/lib/decidim/odoo/api/find_partner_by_vat.rb +21 -0
  28. data/lib/decidim/odoo/api.rb +25 -0
  29. data/lib/decidim/odoo/engine.rb +48 -0
  30. data/lib/decidim/odoo/test/factories.rb +22 -0
  31. data/lib/decidim/odoo/test/shared_contexts.rb +18 -0
  32. data/lib/decidim/odoo/version.rb +10 -0
  33. data/lib/decidim/odoo.rb +42 -0
  34. data/lib/generators/decidim/odoo/install_generator.rb +47 -0
  35. data/lib/generators/decidim/odoo/templates/development_odoo_config.rb +21 -0
  36. data/lib/generators/decidim/odoo/templates/test_odoo_config.rb +20 -0
  37. data/lib/omniauth/strategies/odoo_keycloak.rb +25 -0
  38. data/lib/tasks/decidim_odoo.rake +16 -0
  39. metadata +135 -0
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDecidimOdooUsers < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :decidim_odoo_users do |t|
6
+ t.references :decidim_organization, null: false, foreign_key: { to_table: :decidim_organizations }, index: { name: :index_odoo_users_on_decidim_organization_id }
7
+ t.references :decidim_user, null: false, foreign_key: { to_table: :decidim_users }, index: { name: :index_odoo_users_on_decidim_user_id }
8
+
9
+ t.integer :odoo_user_id
10
+ t.string :ref
11
+ t.boolean :coop_candidate, default: false
12
+ t.boolean :member, default: false
13
+
14
+ t.timestamps
15
+
16
+ t.index %w(decidim_organization_id odoo_user_id), name: "index_unique_odoo_user_and_organization", unique: true
17
+ t.index %w(decidim_organization_id ref), name: "index_unique_ref_and_organization", unique: true
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Odoo
5
+ # This module contains all the domain logic associated to the decidim-odoo
6
+ # module admin panel.
7
+ module Admin
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Odoo
5
+ # This is the engine that runs on the admin interface of decidim-odoo.
6
+ class AdminEngine < ::Rails::Engine
7
+ isolate_namespace Decidim::Odoo::Admin
8
+
9
+ paths["db/migrate"] = nil
10
+ paths["lib/tasks"] = nil
11
+
12
+ routes do
13
+ resources :members, only: [:index] do
14
+ collection do
15
+ get :sync
16
+ end
17
+ end
18
+
19
+ root to: "members#index"
20
+ end
21
+
22
+ initializer "decidim_odoo.webpacker.assets_path" do
23
+ Decidim.register_assets_path File.expand_path("app/packs", root)
24
+ end
25
+
26
+ initializer "decidim.odoo.mount_admin_engine" do
27
+ Decidim::Core::Engine.routes do
28
+ mount Decidim::Odoo::AdminEngine, at: "/admin/odoo", as: "decidim_odoo_admin"
29
+ end
30
+ end
31
+
32
+ initializer "decidim.odoo.admin_menu" do
33
+ Decidim.menu :admin_menu do |menu|
34
+ menu.add_item :odoo,
35
+ "Odoo",
36
+ decidim_odoo_admin.members_path,
37
+ icon_name: "people",
38
+ position: 5.75,
39
+ active: is_active_link?(decidim_odoo_admin.members_path, :inclusive),
40
+ if: defined?(current_user) && current_user&.read_attribute("admin")
41
+ end
42
+ end
43
+
44
+ def load_seed
45
+ nil
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Odoo
5
+ module Api
6
+ module Base
7
+ class BaseQuery
8
+ attr_reader :result, :request
9
+
10
+ def response
11
+ @request.response
12
+ end
13
+
14
+ protected
15
+
16
+ def parsed_response
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def store_result
21
+ @result = parsed_response
22
+ @result = @result.deep_symbolize_keys if @result.is_a? Hash
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Odoo
5
+ module Api
6
+ module Base
7
+ class Request
8
+ def initialize(verify_ssl: true)
9
+ @verify_ssl = verify_ssl
10
+ end
11
+
12
+ attr_accessor :response, :body
13
+
14
+ %w(get post).each do |method|
15
+ define_singleton_method(method) do |path, params: {}, headers: {}, verify_ssl: true|
16
+ instance = Request.new(verify_ssl: verify_ssl)
17
+ response = instance.connection.public_send(method, instance.url(path)) do |request|
18
+ request.params = instance.base_params.merge(params)
19
+ request.headers = instance.base_headers.merge(headers)
20
+ end
21
+
22
+ raise Decidim::Odoo::Error, response.reason_phrase unless response.success?
23
+
24
+ instance.response = JSON.parse(response.body)
25
+ instance
26
+ end
27
+ end
28
+
29
+ def connection
30
+ @connection ||= Faraday.new(ssl: { verify: @verify_ssl })
31
+ end
32
+
33
+ def url(path)
34
+ "#{Decidim::Odoo::Api.base_url}/#{path}"
35
+ end
36
+
37
+ def base_params
38
+ {}
39
+ end
40
+
41
+ def base_headers
42
+ { "api-key" => Decidim::Odoo::Api.api_key }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Odoo
5
+ module Api
6
+ class FindPartner < Base::BaseQuery
7
+ def initialize(ref)
8
+ @request = Base::Request.get("partner/#{ref}")
9
+
10
+ store_result
11
+ end
12
+
13
+ protected
14
+
15
+ def parsed_response
16
+ response
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Odoo
5
+ module Api
6
+ class FindPartnerByVat < Base::BaseQuery
7
+ def initialize(vat)
8
+ @request = Base::Request.get("partner", params: { vat: vat })
9
+
10
+ store_result
11
+ end
12
+
13
+ protected
14
+
15
+ def parsed_response
16
+ response
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "api/base/base_query"
4
+ require_relative "api/base/request"
5
+ require_relative "api/find_partner"
6
+ require_relative "api/find_partner_by_vat"
7
+
8
+ module Decidim
9
+ module Odoo
10
+ # This namespace holds the logic to connect to the Odoo REST API.
11
+ module Api
12
+ def self.config
13
+ Decidim::Odoo.api
14
+ end
15
+
16
+ def self.api_key
17
+ config[:api_key]
18
+ end
19
+
20
+ def self.base_url
21
+ config[:base_url]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "omniauth/strategies/odoo_keycloak"
4
+
5
+ module Decidim
6
+ module Odoo
7
+ # This is the engine that runs on the public interface of odoo.
8
+ class Engine < ::Rails::Engine
9
+ isolate_namespace Decidim::Odoo
10
+
11
+ config.to_prepare do
12
+ Decidim::User.include(Decidim::Odoo::UserOverride)
13
+ end
14
+
15
+ initializer "decidim_odoo.omniauth" do
16
+ next unless Decidim::Odoo.keycloak_omniauth && Decidim::Odoo.keycloak_omniauth[:client_id]
17
+
18
+ Rails.application.config.middleware.use OmniAuth::Builder do
19
+ provider :odoo_keycloak, Decidim::Odoo.keycloak_omniauth[:client_id], Decidim::Odoo.keycloak_omniauth[:client_secret],
20
+ client_options: Decidim::Odoo.keycloak_omniauth[:client_options]
21
+ end
22
+ end
23
+
24
+ initializer "decidim_odoo.user_sync" do
25
+ ActiveSupport::Notifications.subscribe "decidim.user.omniauth_registration" do |_name, data|
26
+ Decidim::Odoo::OmniauthUserSyncJob.perform_later(data) if data[:provider] == Decidim::Odoo::OMNIAUTH_PROVIDER_NAME
27
+ end
28
+ ActiveSupport::Notifications.subscribe "decidim.odoo.user.updated" do |_name, data|
29
+ Decidim::Odoo::AutoVerificationJob.perform_later(data)
30
+ end
31
+ end
32
+
33
+ initializer "decidim_odoo.authorizations" do
34
+ next unless Decidim::Odoo.authorizations
35
+
36
+ if Decidim::Odoo.authorizations.include?(:odoo_member)
37
+ Decidim::Verifications.register_workflow(:odoo_member) do |workflow|
38
+ workflow.form = "Decidim::Odoo::Verifications::OdooMember"
39
+ end
40
+ end
41
+ end
42
+
43
+ initializer "decidim_odoo.webpacker.assets_path" do
44
+ Decidim.register_assets_path File.expand_path("app/packs", root)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/core/test/factories"
4
+
5
+ module Decidim::Odoo::Faker
6
+ class << self
7
+ def vat
8
+ "ES#{Faker::IDNumber.spanish_citizen_number.tr("-", "")}"
9
+ end
10
+ end
11
+ end
12
+
13
+ FactoryBot.define do
14
+ factory :odoo_user, class: "Decidim::Odoo::User" do
15
+ user
16
+ organization { user.organization }
17
+ odoo_user_id { Faker::Number.between(from: 1, to: 100_000) }
18
+ ref { Faker::Number.between(from: 1, to: 100_000).to_s }
19
+ coop_candidate { false }
20
+ member { false }
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_context "with stubs example api" do
4
+ let(:http_method) { :get }
5
+ let(:http_status) { 200 }
6
+ let(:data) { { "foo" => "bar" } }
7
+ let(:params) { {} }
8
+
9
+ before do
10
+ stub_request(http_method, /api\.example\.org/).to_return(status: http_status, body: data.to_json, headers: {})
11
+ end
12
+ end
13
+
14
+ shared_examples_for "no authorization is created" do
15
+ it "does not create an authorization" do
16
+ expect { subject.perform_now(params) }.not_to change(Decidim::Authorization, :count)
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # This holds the decidim-meetings version.
5
+ module Odoo
6
+ VERSION = "0.1.0"
7
+ DECIDIM_VERSION = "0.26.7"
8
+ COMPAT_DECIDIM_VERSION = [">= 0.25.0", "< 0.27"].freeze
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/odoo/admin"
4
+ require "decidim/odoo/admin_engine"
5
+ require "decidim/odoo/api"
6
+ require "decidim/odoo/engine"
7
+
8
+ module Decidim
9
+ # This namespace holds the logic of the `Odoo` component. This component
10
+ # allows users to create odoo in a participatory space.
11
+ module Odoo
12
+ include ActiveSupport::Configurable
13
+
14
+ OMNIAUTH_PROVIDER_NAME = "odoo_keycloak"
15
+
16
+ config_accessor :api do
17
+ {
18
+ base_url: ENV["ODOO_API_BASE_URL"].presence,
19
+ api_key: ENV["ODOO_API_API_KEY"].presence
20
+ }
21
+ end
22
+
23
+ config_accessor :keycloak_omniauth do
24
+ {
25
+ enabled: ENV["OMNIAUTH_ODOO_KEYCLOAK_CLIENT_ID"].present?,
26
+ client_id: ENV["OMNIAUTH_ODOO_KEYCLOAK_CLIENT_ID"].presence,
27
+ client_secret: ENV["OMNIAUTH_ODOO_KEYCLOAK_CLIENT_SECRET"].presence,
28
+ client_options: {
29
+ site: ENV["OMNIAUTH_ODOO_KEYCLOAK_SITE"].presence,
30
+ realm: ENV["OMNIAUTH_ODOO_KEYCLOAK_REALM"].presence
31
+ },
32
+ icon_path: ENV["OMNIAUTH_ODOO_KEYCLOAK_ICON_PATH"].presence || "media/images/odoo_logo.svg"
33
+ }
34
+ end
35
+
36
+ config_accessor :authorizations do
37
+ [:odoo_member]
38
+ end
39
+
40
+ class Error < StandardError; end
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+
5
+ module Decidim
6
+ module Odoo
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ desc "This generator modifies secrets file adding odoo to omniauth methods"
10
+ def secrets
11
+ case Rails.env
12
+ when "development"
13
+ inject_into_file "development_app/config/secrets.yml", after: "icon: phone" do
14
+ <<~YAML
15
+ |
16
+ | odoo_keycloak:
17
+ | enabled: true
18
+ | icon_path: media/images/odoo_logo.svg
19
+ YAML
20
+ .gsub(/^ *\|/, "").rstrip
21
+ end
22
+ when "test"
23
+ inject_into_file "spec/decidim_dummy_app/config/secrets.yml", after: "app_secret: fake-facebook-app-secret" do
24
+ <<~YAML
25
+ |
26
+ | odoo_keycloak:
27
+ | enabled: false
28
+ | icon_path: media/images/odoo_logo.svg
29
+ YAML
30
+ .gsub(/^ *\|/, "").rstrip
31
+ end
32
+ end
33
+ end
34
+
35
+ desc "This generator copies the initializer file"
36
+ def initializers
37
+ Dir.chdir(Rails.env.test? ? "spec/decidim_dummy_app" : "development_app") do
38
+ FileUtils.cp(
39
+ "#{__dir__}/templates/#{Rails.env}_odoo_config.rb",
40
+ "config/initializers/odoo_config.rb"
41
+ )
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ Decidim::Odoo.configure do |config|
4
+ # Configure api credentials
5
+ config.api = {
6
+ base_url: ENV["ODOO_API_BASE_URL"].presence,
7
+ api_key: ENV["ODOO_API_API_KEY"].presence
8
+ }
9
+
10
+ # Configure omniauth secrets
11
+ config.keycloak_omniauth = {
12
+ enabled: ENV["OMNIAUTH_ODOO_KEYCLOAK_CLIENT_ID"].present?,
13
+ client_id: ENV["OMNIAUTH_ODOO_KEYCLOAK_CLIENT_ID"].presence,
14
+ client_secret: ENV["OMNIAUTH_ODOO_KEYCLOAK_CLIENT_SECRET"].presence,
15
+ client_options: {
16
+ site: ENV["OMNIAUTH_ODOO_KEYCLOAK_SITE"].presence,
17
+ realm: ENV["OMNIAUTH_ODOO_KEYCLOAK_REALM"].presence
18
+ },
19
+ icon_path: ENV["OMNIAUTH_ODOO_KEYCLOAK_ICON_PATH"].presence || "media/images/odoo_logo.svg"
20
+ }
21
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ Decidim::Odoo.configure do |config|
4
+ # Configure api credentials
5
+ config.api = {
6
+ base_url: "https://test.odoo.api.example.org",
7
+ api_key: "test-api-key"
8
+ }
9
+
10
+ # Configure omniauth secrets
11
+ config.keycloak_omniauth = {
12
+ enabled: true,
13
+ client_id: "test-client-id",
14
+ client_secret: "test-client-secret",
15
+ client_options: {
16
+ site: "https://test.odoo.oauth.example.org",
17
+ realm: "test-realm"
18
+ }
19
+ }
20
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "omniauth-keycloak"
4
+
5
+ module OmniAuth
6
+ module Strategies
7
+ class OdooKeycloak < OmniAuth::Strategies::KeycloakOpenId
8
+ option :name, "odoo_keycloak"
9
+
10
+ uid { odoo_info[:ref] }
11
+
12
+ info do
13
+ {
14
+ nickname: odoo_info[:vat],
15
+ name: odoo_info[:name],
16
+ email: odoo_info[:email]
17
+ }
18
+ end
19
+
20
+ def odoo_info
21
+ @odoo_info ||= ::Decidim::Odoo::Api::FindPartnerByVat.new(raw_info["preferred_username"]).result
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :decidim do
4
+ namespace :odoo do
5
+ # invoke with 'bundle exec rake "civicrm:sync:groups"'
6
+
7
+ namespace :sync do
8
+ desc "Sync members with Odoo API"
9
+ task members: :environment do
10
+ Decidim::Organization.find_each do |organization|
11
+ Decidim::Odoo::SyncUsersJob.perform_later(organization.id)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: decidim-odoo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Francisco Bolívar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-07-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: decidim-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.25.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '0.27'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.25.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.27'
33
+ - !ruby/object:Gem::Dependency
34
+ name: omniauth-keycloak
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.5'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.5'
47
+ - !ruby/object:Gem::Dependency
48
+ name: decidim-dev
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.25.0
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: '0.27'
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.25.0
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '0.27'
67
+ description: A Decidim module to sync Odoo users who connect to the platform using
68
+ Keycloak OpenID OAuth.
69
+ email:
70
+ - francisco.bolivar@nazaries.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - LICENSE-AGPLv3.txt
76
+ - README.md
77
+ - Rakefile
78
+ - app/commands/decidim/odoo/sync_user.rb
79
+ - app/controllers/concerns/decidim/odoo/admin/members/filterable.rb
80
+ - app/controllers/decidim/odoo/admin/members_controller.rb
81
+ - app/forms/decidim/odoo/verifications/odoo_member.rb
82
+ - app/helpers/decidim/odoo/admin/odoo_helper.rb
83
+ - app/jobs/decidim/odoo/auto_verification_job.rb
84
+ - app/jobs/decidim/odoo/omniauth_user_sync_job.rb
85
+ - app/jobs/decidim/odoo/sync_users_job.rb
86
+ - app/models/concerns/decidim/odoo/user_override.rb
87
+ - app/models/decidim/odoo/user.rb
88
+ - app/packs/entrypoints/decidim_odoo.js
89
+ - app/packs/images/odoo_logo.svg
90
+ - app/views/decidim/odoo/admin/members/index.html.erb
91
+ - config/assets.rb
92
+ - config/i18n-tasks.yml
93
+ - config/locales/en.yml
94
+ - db/migrate/20230713143501_create_decidim_odoo_users.rb
95
+ - lib/decidim/odoo.rb
96
+ - lib/decidim/odoo/admin.rb
97
+ - lib/decidim/odoo/admin_engine.rb
98
+ - lib/decidim/odoo/api.rb
99
+ - lib/decidim/odoo/api/base/base_query.rb
100
+ - lib/decidim/odoo/api/base/request.rb
101
+ - lib/decidim/odoo/api/find_partner.rb
102
+ - lib/decidim/odoo/api/find_partner_by_vat.rb
103
+ - lib/decidim/odoo/engine.rb
104
+ - lib/decidim/odoo/test/factories.rb
105
+ - lib/decidim/odoo/test/shared_contexts.rb
106
+ - lib/decidim/odoo/version.rb
107
+ - lib/generators/decidim/odoo/install_generator.rb
108
+ - lib/generators/decidim/odoo/templates/development_odoo_config.rb
109
+ - lib/generators/decidim/odoo/templates/test_odoo_config.rb
110
+ - lib/omniauth/strategies/odoo_keycloak.rb
111
+ - lib/tasks/decidim_odoo.rake
112
+ homepage: https://github.com/decidim/decidim-module-odoo
113
+ licenses:
114
+ - AGPL-3.0
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '2.7'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubygems_version: 3.2.22
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: A decidim odoo module
135
+ test_files: []