1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-17 11:54:22 +01:00

api endpoint and worker to export accounting data

This commit is contained in:
Sylvain 2019-07-30 11:43:51 +02:00
parent 82ad69d386
commit f772bc3509
9 changed files with 123 additions and 28 deletions

View File

@ -1,5 +1,6 @@
# 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: 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
@ -9,6 +10,7 @@
- Fix some security issues: updated sidekiq to 5.2.7 to fix XSS and CRSF issues
- Removed dependency to jQuery UI
- Updated angular-xeditable, to remove dependency to jquery 1.11.1
- [TODO DEPLOY] `rake db:migrate`
## v4.0.2 2019 July 10

View 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

View File

@ -8,10 +8,17 @@ class API::ExportsController < API::ApiController
def download
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)
send_file File.join(Rails.root, @export.file),
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
type: mime_type,
disposition: 'attachment'
else
render text: I18n.t('errors.messages.export_not_found'), status: :not_found
@ -21,28 +28,8 @@ class API::ExportsController < API::ApiController
def status
authorize Export
export = Export.where(category: params[:category], export_type: params[:type], query: params[:query], key: params[:key])
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
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 export.nil? || !FileTest.exist?(export.file)
render json: { exists: false, id: nil }, status: :ok
@ -53,6 +40,39 @@ class API::ExportsController < API::ApiController
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
@export = Export.find(params[:id])
end

View File

@ -21,7 +21,7 @@ class Export < ActiveRecord::Base
end
def filename
"#{export_type}-#{id}_#{created_at.strftime('%d%m%Y')}.xlsx"
"#{export_type}-#{id}_#{created_at.strftime('%d%m%Y')}.#{extension}"
end
private
@ -34,6 +34,8 @@ class Export < ActiveRecord::Base
UsersExportWorker.perform_async(id)
when 'availabilities'
AvailabilitiesExportWorker.perform_async(id)
when 'accounting'
AccountingExportWorker.perform_async(id)
else
raise NoMethodError, "Unknown export service for #{category}/#{export_type}"
end

View 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

View 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

View File

@ -135,6 +135,8 @@ Rails.application.routes.draw do
get 'last_closing_end', on: :collection
get 'archive', action: 'download_archive', on: :member
end
# export accounting data to csv or equivalent
post 'accounting/export' => 'accounting_exports#export'
# i18n
# regex allows using dots in URL for 'state'

View File

@ -0,0 +1,5 @@
class AddExtensionToExport < ActiveRecord::Migration
def change
add_column :exports, :extension, :string, default: 'xlsx'
end
end

View File

@ -11,12 +11,12 @@
#
# 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
enable_extension "plpgsql"
enable_extension "unaccent"
enable_extension "pg_trgm"
enable_extension "unaccent"
create_table "abuses", force: :cascade do |t|
t.integer "signaled_id"
@ -202,10 +202,11 @@ ActiveRecord::Schema.define(version: 20190606074801) do
t.string "category"
t.string "export_type"
t.string "query"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "key"
t.string "extension", default: "xlsx"
end
add_index "exports", ["user_id"], name: "index_exports_on_user_id", using: :btree