mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-19 13:54:25 +01:00
api endpoint and worker to export accounting data
This commit is contained in:
parent
82ad69d386
commit
f772bc3509
@ -1,5 +1,6 @@
|
|||||||
# Changelog Fab Manager
|
# Changelog Fab Manager
|
||||||
|
|
||||||
|
- Ability to configure and export the accounting data to the ACD accounting software
|
||||||
- Fix a bug: no user can be created after the last member was deleted
|
- Fix a bug: no user can be created after the last member was deleted
|
||||||
- Fix a bug: unable to generate a refund (Avoir)
|
- Fix a bug: unable to generate a refund (Avoir)
|
||||||
- Fix a bug: a newly generated refund is displayed as broken (unchained record) even if it is correctly chained
|
- Fix a bug: a newly generated refund is displayed as broken (unchained record) even if it is correctly chained
|
||||||
@ -9,6 +10,7 @@
|
|||||||
- Fix some security issues: updated sidekiq to 5.2.7 to fix XSS and CRSF issues
|
- Fix some security issues: updated sidekiq to 5.2.7 to fix XSS and CRSF issues
|
||||||
- Removed dependency to jQuery UI
|
- Removed dependency to jQuery UI
|
||||||
- Updated angular-xeditable, to remove dependency to jquery 1.11.1
|
- Updated angular-xeditable, to remove dependency to jquery 1.11.1
|
||||||
|
- [TODO DEPLOY] `rake db:migrate`
|
||||||
|
|
||||||
## v4.0.2 2019 July 10
|
## v4.0.2 2019 July 10
|
||||||
|
|
||||||
|
34
app/controllers/api/accounting_exports_controller.rb
Normal file
34
app/controllers/api/accounting_exports_controller.rb
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# API Controller for exporting accounting data to external accounting softwares
|
||||||
|
class API::AccountingExportsController < API::ApiController
|
||||||
|
|
||||||
|
before_action :authenticate_user!
|
||||||
|
|
||||||
|
def export
|
||||||
|
authorize :export
|
||||||
|
|
||||||
|
export = Export.where(category: 'accounting', export_type: 'accounting-software')
|
||||||
|
.where('created_at > ?', Invoice.maximum('updated_at'))
|
||||||
|
.last
|
||||||
|
if export.nil? || !FileTest.exist?(export.file)
|
||||||
|
@export = Export.new(
|
||||||
|
category: 'accounting',
|
||||||
|
export_type: 'accounting-software',
|
||||||
|
user: current_user,
|
||||||
|
extension: params[:extension],
|
||||||
|
query: params[:query],
|
||||||
|
key: params[:separator]
|
||||||
|
)
|
||||||
|
if @export.save
|
||||||
|
render json: { export_id: @export.id }, status: :ok
|
||||||
|
else
|
||||||
|
render json: @export.errors, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
else
|
||||||
|
send_file File.join(Rails.root, export.file),
|
||||||
|
type: 'text/csv',
|
||||||
|
disposition: 'attachment'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -8,10 +8,17 @@ class API::ExportsController < API::ApiController
|
|||||||
|
|
||||||
def download
|
def download
|
||||||
authorize @export
|
authorize @export
|
||||||
|
mime_type = if @export.extension == 'xlsx'
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
|
elsif @export.extension == 'csv'
|
||||||
|
'text/csv'
|
||||||
|
else
|
||||||
|
'application/octet-stream'
|
||||||
|
end
|
||||||
|
|
||||||
if FileTest.exist?(@export.file)
|
if FileTest.exist?(@export.file)
|
||||||
send_file File.join(Rails.root, @export.file),
|
send_file File.join(Rails.root, @export.file),
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
type: mime_type,
|
||||||
disposition: 'attachment'
|
disposition: 'attachment'
|
||||||
else
|
else
|
||||||
render text: I18n.t('errors.messages.export_not_found'), status: :not_found
|
render text: I18n.t('errors.messages.export_not_found'), status: :not_found
|
||||||
@ -21,28 +28,8 @@ class API::ExportsController < API::ApiController
|
|||||||
def status
|
def status
|
||||||
authorize Export
|
authorize Export
|
||||||
|
|
||||||
export = Export.where(category: params[:category], export_type: params[:type], query: params[:query], key: params[:key])
|
exports = Export.where(category: params[:category], export_type: params[:type], query: params[:query], key: params[:key])
|
||||||
|
export = retrieve_last_export(exports, params[:category], params[:type])
|
||||||
if params[:category] == 'users'
|
|
||||||
case params[:type]
|
|
||||||
when 'subscriptions'
|
|
||||||
export = export.where('created_at > ?', Subscription.maximum('updated_at'))
|
|
||||||
when 'reservations'
|
|
||||||
export = export.where('created_at > ?', Reservation.maximum('updated_at'))
|
|
||||||
when 'members'
|
|
||||||
export = export.where('created_at > ?', User.with_role(:member).maximum('updated_at'))
|
|
||||||
else
|
|
||||||
raise ArgumentError, "Unknown export users/#{params[:type]}"
|
|
||||||
end
|
|
||||||
elsif params[:category] == 'availabilities'
|
|
||||||
case params[:type]
|
|
||||||
when 'index'
|
|
||||||
export = export.where('created_at > ?', [Availability.maximum('updated_at'), Reservation.maximum('updated_at')].max)
|
|
||||||
else
|
|
||||||
raise ArgumentError, "Unknown type availabilities/#{params[:type]}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
export = export.last
|
|
||||||
|
|
||||||
if export.nil? || !FileTest.exist?(export.file)
|
if export.nil? || !FileTest.exist?(export.file)
|
||||||
render json: { exists: false, id: nil }, status: :ok
|
render json: { exists: false, id: nil }, status: :ok
|
||||||
@ -53,6 +40,39 @@ class API::ExportsController < API::ApiController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def retrieve_last_export(export, category, type)
|
||||||
|
case category
|
||||||
|
when 'users'
|
||||||
|
case type
|
||||||
|
when 'subscriptions'
|
||||||
|
export = export.where('created_at > ?', Subscription.maximum('updated_at'))
|
||||||
|
when 'reservations'
|
||||||
|
export = export.where('created_at > ?', Reservation.maximum('updated_at'))
|
||||||
|
when 'members'
|
||||||
|
export = export.where('created_at > ?', User.with_role(:member).maximum('updated_at'))
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Unknown export users/#{type}"
|
||||||
|
end
|
||||||
|
when 'availabilities'
|
||||||
|
case type
|
||||||
|
when 'index'
|
||||||
|
export = export.where('created_at > ?', [Availability.maximum('updated_at'), Reservation.maximum('updated_at')].max)
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Unknown type availabilities/#{type}"
|
||||||
|
end
|
||||||
|
when 'accounting'
|
||||||
|
case type
|
||||||
|
when 'accounting-software'
|
||||||
|
export = export.where('created_at > ?', Invoice.maximum('updated_at'))
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Unknown type accounting/#{type}"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Unknown category #{category}"
|
||||||
|
end
|
||||||
|
export.last
|
||||||
|
end
|
||||||
|
|
||||||
def set_export
|
def set_export
|
||||||
@export = Export.find(params[:id])
|
@export = Export.find(params[:id])
|
||||||
end
|
end
|
||||||
|
@ -21,7 +21,7 @@ class Export < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def filename
|
def filename
|
||||||
"#{export_type}-#{id}_#{created_at.strftime('%d%m%Y')}.xlsx"
|
"#{export_type}-#{id}_#{created_at.strftime('%d%m%Y')}.#{extension}"
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -34,6 +34,8 @@ class Export < ActiveRecord::Base
|
|||||||
UsersExportWorker.perform_async(id)
|
UsersExportWorker.perform_async(id)
|
||||||
when 'availabilities'
|
when 'availabilities'
|
||||||
AvailabilitiesExportWorker.perform_async(id)
|
AvailabilitiesExportWorker.perform_async(id)
|
||||||
|
when 'accounting'
|
||||||
|
AccountingExportWorker.perform_async(id)
|
||||||
else
|
else
|
||||||
raise NoMethodError, "Unknown export service for #{category}/#{export_type}"
|
raise NoMethodError, "Unknown export service for #{category}/#{export_type}"
|
||||||
end
|
end
|
||||||
|
8
app/policies/accounting_exports_policy.rb
Normal file
8
app/policies/accounting_exports_policy.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Check the access policies for API::AccountingExportsController
|
||||||
|
class AccountingExportsPolicy < ApplicationPolicy
|
||||||
|
def export?
|
||||||
|
user.admin?
|
||||||
|
end
|
||||||
|
end
|
21
app/workers/accounting_export_worker.rb
Normal file
21
app/workers/accounting_export_worker.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Asynchronously export the accounting data (Invoices & Avoirs) to an external accounting software
|
||||||
|
class AccountingExportWorker
|
||||||
|
include Sidekiq::Worker
|
||||||
|
|
||||||
|
def perform(export_id)
|
||||||
|
export = Export.find(export_id)
|
||||||
|
|
||||||
|
raise SecurityError, 'Not allowed to export' unless export.user.admin?
|
||||||
|
|
||||||
|
data = JSON.parse(export.query)
|
||||||
|
service = AccountingExportService.new(export.file, data['columns'], data['encoding'], export.extension, export.key)
|
||||||
|
|
||||||
|
service.export(data['start_date'], data['end_date'])
|
||||||
|
|
||||||
|
NotificationCenter.call type: :notify_admin_export_complete,
|
||||||
|
receiver: export.user,
|
||||||
|
attached_object: export
|
||||||
|
end
|
||||||
|
end
|
@ -135,6 +135,8 @@ Rails.application.routes.draw do
|
|||||||
get 'last_closing_end', on: :collection
|
get 'last_closing_end', on: :collection
|
||||||
get 'archive', action: 'download_archive', on: :member
|
get 'archive', action: 'download_archive', on: :member
|
||||||
end
|
end
|
||||||
|
# export accounting data to csv or equivalent
|
||||||
|
post 'accounting/export' => 'accounting_exports#export'
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
# regex allows using dots in URL for 'state'
|
# regex allows using dots in URL for 'state'
|
||||||
|
5
db/migrate/20190730085826_add_extension_to_export.rb
Normal file
5
db/migrate/20190730085826_add_extension_to_export.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class AddExtensionToExport < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :exports, :extension, :string, default: 'xlsx'
|
||||||
|
end
|
||||||
|
end
|
@ -11,12 +11,12 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20190606074801) do
|
ActiveRecord::Schema.define(version: 20190730085826) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
enable_extension "unaccent"
|
|
||||||
enable_extension "pg_trgm"
|
enable_extension "pg_trgm"
|
||||||
|
enable_extension "unaccent"
|
||||||
|
|
||||||
create_table "abuses", force: :cascade do |t|
|
create_table "abuses", force: :cascade do |t|
|
||||||
t.integer "signaled_id"
|
t.integer "signaled_id"
|
||||||
@ -202,10 +202,11 @@ ActiveRecord::Schema.define(version: 20190606074801) do
|
|||||||
t.string "category"
|
t.string "category"
|
||||||
t.string "export_type"
|
t.string "export_type"
|
||||||
t.string "query"
|
t.string "query"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.string "key"
|
t.string "key"
|
||||||
|
t.string "extension", default: "xlsx"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "exports", ["user_id"], name: "index_exports_on_user_id", using: :btree
|
add_index "exports", ["user_id"], name: "index_exports_on_user_id", using: :btree
|
||||||
|
Loading…
x
Reference in New Issue
Block a user