effective_qb_sync 1.0.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +94 -0
- data/Rakefile +21 -0
- data/app/controllers/admin/qb_syncs_controller.rb +60 -0
- data/app/controllers/effective/qb_sync_controller.rb +40 -0
- data/app/models/effective/access_denied.rb +17 -0
- data/app/models/effective/datatables/qb_syncs.rb +30 -0
- data/app/models/effective/qb_log.rb +13 -0
- data/app/models/effective/qb_machine.rb +281 -0
- data/app/models/effective/qb_order_item.rb +13 -0
- data/app/models/effective/qb_order_items_form.rb +55 -0
- data/app/models/effective/qb_request.rb +262 -0
- data/app/models/effective/qb_ticket.rb +55 -0
- data/app/models/effective/qbwc_supervisor.rb +89 -0
- data/app/views/admin/qb_syncs/_actions.html.haml +2 -0
- data/app/views/admin/qb_syncs/_qb_item_names.html.haml +9 -0
- data/app/views/admin/qb_syncs/index.html.haml +24 -0
- data/app/views/admin/qb_syncs/instructions.html.haml +136 -0
- data/app/views/admin/qb_syncs/show.html.haml +52 -0
- data/app/views/effective/orders_mailer/qb_sync_error.html.haml +56 -0
- data/app/views/effective/qb_sync/authenticate.erb +12 -0
- data/app/views/effective/qb_sync/clientVersion.erb +8 -0
- data/app/views/effective/qb_sync/closeConnection.erb +8 -0
- data/app/views/effective/qb_sync/connectionError.erb +9 -0
- data/app/views/effective/qb_sync/getLastError.erb +9 -0
- data/app/views/effective/qb_sync/receiveResponseXML.erb +8 -0
- data/app/views/effective/qb_sync/sendRequestXML.erb +8 -0
- data/app/views/effective/qb_sync/serverVersion.erb +8 -0
- data/app/views/effective/qb_web_connector/quickbooks.qwc.erb +12 -0
- data/config/routes.rb +16 -0
- data/db/migrate/01_create_effective_qb_sync.rb.erb +68 -0
- data/lib/effective_qb_sync/engine.rb +42 -0
- data/lib/effective_qb_sync/version.rb +3 -0
- data/lib/effective_qb_sync.rb +42 -0
- data/lib/generators/effective_qb_sync/install_generator.rb +42 -0
- data/lib/generators/templates/effective_qb_sync.rb +61 -0
- data/lib/generators/templates/effective_qb_sync_mailer_preview.rb +39 -0
- data/spec/dummy/README.rdoc +8 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/product.rb +14 -0
- data/spec/dummy/app/models/product_with_float_price.rb +13 -0
- data/spec/dummy/app/models/user.rb +14 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +32 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/devise.rb +254 -0
- data/spec/dummy/config/initializers/effective_addresses.rb +15 -0
- data/spec/dummy/config/initializers/effective_orders.rb +154 -0
- data/spec/dummy/config/initializers/effective_qb_sync.rb +41 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/simple_form.rb +189 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/schema.rb +208 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +90 -0
- data/spec/dummy/log/test.log +1 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/fixtures/qbxml_response_error.xml +6 -0
- data/spec/fixtures/qbxml_response_success.xml +621 -0
- data/spec/models/acts_as_purchasable_spec.rb +131 -0
- data/spec/models/factories_spec.rb +32 -0
- data/spec/models/qb_machine_spec.rb +554 -0
- data/spec/models/qb_request_spec.rb +327 -0
- data/spec/models/qb_ticket_spec.rb +62 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/support/factories.rb +97 -0
- metadata +397 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module EffectiveQbSync
|
|
2
|
+
class Engine < ::Rails::Engine
|
|
3
|
+
engine_name 'effective_qb_sync'
|
|
4
|
+
|
|
5
|
+
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
|
|
6
|
+
|
|
7
|
+
# Set up our default configuration options.
|
|
8
|
+
initializer "effective_qb_sync.defaults", before: :load_config_initializers do |app|
|
|
9
|
+
eval File.read("#{config.root}/lib/generators/templates/effective_qb_sync.rb")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Ensure every acts_as_purchasable object responds to qb_item_name
|
|
13
|
+
initializer 'effective_qb_sync.assert_qb_item_names_present' do |app|
|
|
14
|
+
if Rails.env.development?
|
|
15
|
+
Rails.application.eager_load!
|
|
16
|
+
|
|
17
|
+
invalids = ActsAsPurchasable.descendants.reject { |klass| klass.new().try(:qb_item_name).present? }
|
|
18
|
+
|
|
19
|
+
if invalids.present?
|
|
20
|
+
raise "expected acts_as_purchasable objects #{invalids.map(&:to_s).to_sentence} .qb_item_name() to be present."
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Include acts_as_addressable concern and allow any ActiveRecord object to call it
|
|
26
|
+
initializer 'effective_qb_sync.active_record' do |app|
|
|
27
|
+
Rails.application.config.to_prepare do
|
|
28
|
+
ActiveSupport.on_load :active_record do
|
|
29
|
+
Effective::OrderItem.class_eval do
|
|
30
|
+
has_one :qb_order_item
|
|
31
|
+
|
|
32
|
+
# first or build
|
|
33
|
+
def qb_item_name
|
|
34
|
+
(qb_order_item || build_qb_order_item(name: purchasable.try(:qb_item_name))).name
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'haml-rails'
|
|
2
|
+
require 'simple_form'
|
|
3
|
+
require 'effective_orders'
|
|
4
|
+
require 'effective_qb_sync/engine'
|
|
5
|
+
require 'effective_qb_sync/version'
|
|
6
|
+
|
|
7
|
+
module EffectiveQbSync
|
|
8
|
+
# The following are all valid config keys
|
|
9
|
+
mattr_accessor :qb_requests_table_name
|
|
10
|
+
mattr_accessor :qb_tickets_table_name
|
|
11
|
+
mattr_accessor :qb_logs_table_name
|
|
12
|
+
mattr_accessor :qb_order_items_table_name
|
|
13
|
+
|
|
14
|
+
mattr_accessor :authorization_method
|
|
15
|
+
|
|
16
|
+
mattr_accessor :quickbooks_username
|
|
17
|
+
mattr_accessor :quickbooks_password
|
|
18
|
+
mattr_accessor :quickbooks_tax_name
|
|
19
|
+
|
|
20
|
+
mattr_accessor :error_email
|
|
21
|
+
|
|
22
|
+
mattr_accessor :layout
|
|
23
|
+
mattr_accessor :admin_simple_form_options
|
|
24
|
+
|
|
25
|
+
def self.setup
|
|
26
|
+
yield self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.authorized?(controller, action, resource)
|
|
30
|
+
if authorization_method.respond_to?(:call) || authorization_method.kind_of?(Symbol)
|
|
31
|
+
raise Effective::AccessDenied.new() unless (controller || self).instance_exec(controller, action, resource, &authorization_method)
|
|
32
|
+
end
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.permitted_params
|
|
37
|
+
[
|
|
38
|
+
:note
|
|
39
|
+
]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module EffectiveQbSync
|
|
2
|
+
module Generators
|
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
|
4
|
+
include Rails::Generators::Migration
|
|
5
|
+
|
|
6
|
+
desc "Creates an EffectiveQbSync initializer in your application."
|
|
7
|
+
|
|
8
|
+
source_root File.expand_path("../../templates", __FILE__)
|
|
9
|
+
|
|
10
|
+
def self.next_migration_number(dirname)
|
|
11
|
+
if not ActiveRecord::Base.timestamped_migrations
|
|
12
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
|
13
|
+
else
|
|
14
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def copy_initializer
|
|
19
|
+
template "effective_qb_sync.rb", "config/initializers/effective_qb_sync.rb"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def copy_mailer_preview
|
|
23
|
+
mailer_preview_path = (Rails.application.config.action_mailer.preview_path rescue nil)
|
|
24
|
+
|
|
25
|
+
if mailer_preview_path.present?
|
|
26
|
+
template 'effective_qb_sync_mailer_preview.rb', File.join(mailer_preview_path, 'effective_qb_sync_mailer_preview.rb')
|
|
27
|
+
else
|
|
28
|
+
puts "couldn't find action_mailer.preview_path. Skipping effective_qb_sync_mailer_preview."
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def create_migration_file
|
|
33
|
+
@qb_requests_table_name = ':' + EffectiveQbSync.qb_requests_table_name.to_s
|
|
34
|
+
@qb_tickets_table_name = ':' + EffectiveQbSync.qb_tickets_table_name.to_s
|
|
35
|
+
@qb_logs_table_name = ':' + EffectiveQbSync.qb_logs_table_name.to_s
|
|
36
|
+
@qb_order_items_table_name = ':' + EffectiveQbSync.qb_order_items_table_name.to_s
|
|
37
|
+
|
|
38
|
+
migration_template '../../../db/migrate/01_create_effective_qb_sync.rb.erb', 'db/migrate/create_effective_qb_sync.rb'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# EffectiveQbSync Rails Engine
|
|
2
|
+
|
|
3
|
+
EffectiveQbSync.setup do |config|
|
|
4
|
+
# Configure Database Tables
|
|
5
|
+
config.qb_requests_table_name = :qb_requests
|
|
6
|
+
config.qb_tickets_table_name = :qb_tickets
|
|
7
|
+
config.qb_logs_table_name = :qb_logs
|
|
8
|
+
config.qb_order_items_table_name = :qb_order_items
|
|
9
|
+
|
|
10
|
+
# Authorization Method
|
|
11
|
+
#
|
|
12
|
+
# This method is called by all controller actions with the appropriate action and resource
|
|
13
|
+
# If the method returns false, an Effective::AccessDenied Error will be raised (see README.md for complete info)
|
|
14
|
+
#
|
|
15
|
+
# Use via Proc (and with CanCan):
|
|
16
|
+
# config.authorization_method = Proc.new { |controller, action, resource| authorize!(action, resource) }
|
|
17
|
+
#
|
|
18
|
+
# Use via custom method:
|
|
19
|
+
# config.authorization_method = :my_authorization_method
|
|
20
|
+
#
|
|
21
|
+
# And then in your application_controller.rb:
|
|
22
|
+
#
|
|
23
|
+
# def my_authorization_method(action, resource)
|
|
24
|
+
# current_user.is?(:admin)
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# Or disable the check completely:
|
|
28
|
+
# config.authorization_method = false
|
|
29
|
+
config.authorization_method = Proc.new { |controller, action, resource| true }
|
|
30
|
+
|
|
31
|
+
# All EffectiveQbSync controllers will use this layout
|
|
32
|
+
config.layout = 'application'
|
|
33
|
+
|
|
34
|
+
# SimpleForm Options
|
|
35
|
+
# This Hash of options will be passed into any admin facing simple_form_for() calls
|
|
36
|
+
config.admin_simple_form_options = {} # For the /admin/qb_syncs form
|
|
37
|
+
|
|
38
|
+
# Quickbooks Company File Settings
|
|
39
|
+
|
|
40
|
+
# The username / password of the Quickbooks user that should be allowed to synchronize.
|
|
41
|
+
# This must match the user configured in the Quickbooks .qwc file
|
|
42
|
+
config.quickbooks_username = ''
|
|
43
|
+
config.quickbooks_password = ''
|
|
44
|
+
|
|
45
|
+
# Sales tax can be added to an order in two ways:
|
|
46
|
+
# 1. Sales tax should be added by Quickbooks
|
|
47
|
+
# - Set below: config.quickbooks_tax_name = ''
|
|
48
|
+
# - In Quickbooks: Edit -> Preferences -> Sales Tax -> Company Preferences -> Do you charge sales tax? Yes
|
|
49
|
+
# 2. Sales tax should be added by the website
|
|
50
|
+
# - Set below: config.quickbooks_tax_name = 'GST Collected'
|
|
51
|
+
# - In Quickbooks: Edit -> Preferences -> Sales Tax -> Company Preferences -> Do you charge sales tax? No
|
|
52
|
+
# - In Quickbooks: Add a regular Quickbooks Item matching the config.quickbooks_tax_name
|
|
53
|
+
# See /admin/qb_syncs/instructions for more information.
|
|
54
|
+
config.quickbooks_tax_name = ''
|
|
55
|
+
|
|
56
|
+
# If a synchronization errors occurs, send an email with steps to fix the error, to this address
|
|
57
|
+
# Uses effective_orders mailer layout and settings
|
|
58
|
+
# Leave nil to use EffectiveOrders.mailer[:admin_email] value, or provide a to email address here
|
|
59
|
+
config.error_email = nil
|
|
60
|
+
|
|
61
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# In Rails 4.1 and above, visit:
|
|
2
|
+
# http://localhost:3000/rails/mailers
|
|
3
|
+
# to see a preview of the following emails:
|
|
4
|
+
|
|
5
|
+
class EffectiveQbSyncMailerPreview < ActionMailer::Preview
|
|
6
|
+
# All order_errors are called from QbTicket.error!
|
|
7
|
+
# There are 3 general types of errors that occur
|
|
8
|
+
|
|
9
|
+
def error_record_does_not_exist
|
|
10
|
+
order_error('Invalid argument. The specified record does not exist in the list.')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def error_invalid_reference_to_item
|
|
14
|
+
order_error('There is an invalid reference to QuickBooks Item "Tax On Sale" in the SalesReceipt line.')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def error_element_already_in_use
|
|
18
|
+
order_error('The name "Peter Pan" of the list element is already in use.')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def error_unknown
|
|
22
|
+
order_error('unknown')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def order_error(error)
|
|
28
|
+
order = Effective::Order.new()
|
|
29
|
+
|
|
30
|
+
Effective::OrdersMailer.order_error(
|
|
31
|
+
order: order,
|
|
32
|
+
error: error,
|
|
33
|
+
to: EffectiveQbSync.error_email,
|
|
34
|
+
subject: "Quickbooks failed to synchronize order ##{order.to_param}",
|
|
35
|
+
template: 'qb_sync_error'
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
data/spec/dummy/Rakefile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
|
2
|
+
// listed below.
|
|
3
|
+
//
|
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
|
6
|
+
//
|
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
|
8
|
+
// compiled file.
|
|
9
|
+
//
|
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
|
11
|
+
// about supported directives.
|
|
12
|
+
//
|
|
13
|
+
//= require_tree .
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
3
|
+
* listed below.
|
|
4
|
+
*
|
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
|
7
|
+
*
|
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any styles
|
|
10
|
+
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
|
11
|
+
* file per style scope.
|
|
12
|
+
*
|
|
13
|
+
*= require_tree .
|
|
14
|
+
*= require_self
|
|
15
|
+
*/
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class User < ActiveRecord::Base
|
|
2
|
+
devise :database_authenticatable, :registerable, :rememberable, :recoverable, :trackable, :validatable, :authentication_keys => [:email]
|
|
3
|
+
|
|
4
|
+
acts_as_addressable :billing, :shipping
|
|
5
|
+
|
|
6
|
+
def to_s
|
|
7
|
+
email
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def phone
|
|
11
|
+
'555-555-5555'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Dummy</title>
|
|
5
|
+
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
|
|
6
|
+
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
|
|
7
|
+
<%= csrf_meta_tags %>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
|
|
11
|
+
<%= yield %>
|
|
12
|
+
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
data/spec/dummy/bin/rake
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
|
2
|
+
|
|
3
|
+
require 'rails/all'
|
|
4
|
+
|
|
5
|
+
Bundler.require(*Rails.groups)
|
|
6
|
+
require 'devise'
|
|
7
|
+
require 'haml'
|
|
8
|
+
require 'effective_addresses'
|
|
9
|
+
require 'effective_orders'
|
|
10
|
+
require 'effective_qb_sync'
|
|
11
|
+
|
|
12
|
+
module Dummy
|
|
13
|
+
class Application < Rails::Application
|
|
14
|
+
# Settings in config/environments/* take precedence over those specified here.
|
|
15
|
+
# Application configuration should go into files in config/initializers
|
|
16
|
+
# -- all .rb files in that directory are automatically loaded.
|
|
17
|
+
|
|
18
|
+
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
|
19
|
+
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
|
20
|
+
# config.time_zone = 'Central Time (US & Canada)'
|
|
21
|
+
|
|
22
|
+
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
|
23
|
+
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
|
24
|
+
# config.i18n.default_locale = :de
|
|
25
|
+
|
|
26
|
+
config.generators do |g|
|
|
27
|
+
g.template_engine :haml
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# SQLite version 3.x
|
|
2
|
+
# gem install sqlite3
|
|
3
|
+
#
|
|
4
|
+
# Ensure the SQLite 3 gem is defined in your Gemfile
|
|
5
|
+
# gem 'sqlite3'
|
|
6
|
+
#
|
|
7
|
+
default: &default
|
|
8
|
+
adapter: sqlite3
|
|
9
|
+
pool: 5
|
|
10
|
+
timeout: 5000
|
|
11
|
+
|
|
12
|
+
development:
|
|
13
|
+
<<: *default
|
|
14
|
+
database: db/development.sqlite3
|
|
15
|
+
|
|
16
|
+
# Warning: The database defined as "test" will be erased and
|
|
17
|
+
# re-generated from your development database when you run "rake".
|
|
18
|
+
# Do not set this db to the same as development or production.
|
|
19
|
+
test:
|
|
20
|
+
<<: *default
|
|
21
|
+
database: db/test.sqlite3
|
|
22
|
+
|
|
23
|
+
production:
|
|
24
|
+
<<: *default
|
|
25
|
+
database: db/production.sqlite3
|