1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-19 13:54:25 +01:00

[ongoing] fixes for invoices pdf files

This commit is contained in:
Sylvain 2019-06-11 16:56:11 +02:00
parent 02a4660a76
commit 86ded2b8d2
17 changed files with 103 additions and 45 deletions

View File

@ -72,8 +72,8 @@ Application.Controllers.controller('MembersController', ['$scope', 'Member', 'me
/**
* Controller used when editing the current user's profile
*/
Application.Controllers.controller('EditProfileController', ['$scope', '$rootScope', '$state', '$window', 'Member', 'Auth', 'Session', 'activeProviderPromise', 'growl', 'dialogs', 'CSRF', 'memberPromise', 'groups', '_t',
function ($scope, $rootScope, $state, $window, Member, Auth, Session, activeProviderPromise, growl, dialogs, CSRF, memberPromise, groups, _t) {
Application.Controllers.controller('EditProfileController', ['$scope', '$rootScope', '$state', '$window', '$sce', 'Member', 'Auth', 'Session', 'activeProviderPromise', 'growl', 'dialogs', 'CSRF', 'memberPromise', 'groups', '_t',
function ($scope, $rootScope, $state, $window, $sce, Member, Auth, Session, activeProviderPromise, growl, dialogs, CSRF, memberPromise, groups, _t) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
@ -194,7 +194,13 @@ Application.Controllers.controller('EditProfileController', ['$scope', '$rootSco
object () {
return {
title: _t('confirmation_required'),
msg: _t('do_you_really_want_to_delete_your_account') + ' ' + _t('all_data_relative_to_your_projects_will_be_lost')
msg: $sce.trustAsHtml(
_t('confirm_delete_your_account') + '<br/>' +
'<strong>' + _t('all_data_will_be_lost') + '</strong><br/><br/>' +
_t('invoicing_data_kept') + '<br/>' +
_t('statistic_data_anonymized') + '<br/>' +
_t('no_further_access_to_projects')
)
};
}
}

View File

@ -83,7 +83,9 @@
<td ng-if="!invoice.is_avoir">{{ invoice.date | amDateFormat:'L LTS' }}</td>
<td ng-if="invoice.is_avoir">{{ invoice.date | amDateFormat:'L' }}</td>
<td>{{ invoice.total | currency}}</td>
<td><a href="" ui-sref="app.admin.members_edit({id: invoice.user_id})">{{ invoice.name }} </a>
<td>
<a href="" ui-sref="app.admin.members_edit({id: invoice.user_id})" ng-show="invoice.user_id">{{ invoice.name }}</a>
<span ng-hide="invoice.user_id">{{ invoice.name }}</span>
<td>
<div class="buttons">
<a class="btn btn-default" ng-href="api/invoices/{{invoice.id}}/download" target="_blank" ng-if="!invoice.is_avoir">

View File

@ -78,7 +78,7 @@
</div>
</div>
<div class="widget-content no-bg text-center auto wrapper">
<button class="btn text-white btn-danger btn-sm" ng-click="deleteUser(user)"><i class="fa fa-warning"></i> {{ 'delete_my_account' | translate }}</button>
<button class="btn text-white btn-danger btn-sm" ng-click="deleteUser(user)"><i class="fa fa-warning m-r-xs"></i> {{ 'delete_my_account' | translate }}</button>
</div>
</div>

View File

@ -65,7 +65,7 @@ class API::MembersController < API::ApiController
def destroy
authorize @member
@member.soft_destroy
@member.destroy
sign_out(@member)
head :no_content
end

View File

@ -31,9 +31,9 @@ class Invoice < ActiveRecord::Base
validates_with ClosedPeriodValidator
def file
dir = "invoices/#{user.id}"
dir = "invoices/#{invoicing_profile.id}"
# create directories if they doesn't exists (invoice & user_id)
# create directories if they doesn't exists (invoice & invoicing_profile_id)
FileUtils.mkdir_p dir
"#{dir}/#{filename}"
end
@ -142,7 +142,7 @@ class Invoice < ActiveRecord::Base
# for debug & used by rake task "fablab:maintenance:regenerate_invoices"
def regenerate_invoice_pdf
pdf = ::PDF::Invoice.new(self, nil).render
pdf = ::PDF::Invoice.new(self, subscription&.expiration_date).render
File.binwrite(file, pdf)
end
@ -211,9 +211,12 @@ class Invoice < ActiveRecord::Base
##
# Check if the current invoice is about a training that was previously validated for the concerned user.
# In that case refunding the invoice shouldn't be allowed.
# Moreover, an invoice cannot be refunded if the users' account was deleted
# @return {Boolean}
##
def prevent_refund?
return true if user.nil?
if invoiced_type == 'Reservation' && invoiced.reservable_type == 'Training'
user.trainings.include?(invoiced.reservable_id)
else

View File

@ -227,7 +227,7 @@ class Reservation < ActiveRecord::Base
def save_with_payment(operator_id, coupon_code = nil)
begin
clean_pending_strip_invoice_items
build_invoice(invoicing_profile: user.invoicing_profile, operator_id: operator_id)
build_invoice(invoicing_profile: user.invoicing_profile, statistic_profile: user.statistic_profile, operator_id: operator_id)
invoice_items = generate_invoice_items(false, coupon_code)
rescue StandardError => e
logger.error e
@ -369,7 +369,7 @@ class Reservation < ActiveRecord::Base
end
def save_with_local_payment(operator_id, coupon_code = nil)
build_invoice(invoicing_profile: user.invoicing_profile, operator_id: operator_id)
build_invoice(invoicing_profile: user.invoicing_profile, statistic_profile: user.statistic_profile, operator_id: operator_id)
generate_invoice_items(true, coupon_code)
return false unless valid?

View File

@ -165,8 +165,22 @@ class Subscription < ActiveRecord::Base
end
end
invoice = Invoice.new(invoiced_id: id, invoiced_type: 'Subscription', invoicing_profile: user.invoicing_profile, total: total, stp_invoice_id: stp_invoice_id, coupon_id: coupon_id, operator_id: operator_id)
invoice.invoice_items.push InvoiceItem.new(amount: plan.amount, stp_invoice_item_id: stp_subscription_id, description: plan.name, subscription_id: self.id)
invoice = Invoice.new(
invoiced_id: id,
invoiced_type: 'Subscription',
invoicing_profile: user.invoicing_profile,
statistic_profile: user.statistic_profile,
total: total,
stp_invoice_id: stp_invoice_id,
coupon_id: coupon_id,
operator_id: operator_id
)
invoice.invoice_items.push InvoiceItem.new(
amount: plan.amount,
stp_invoice_item_id: stp_subscription_id,
description: plan.name,
subscription_id: id
)
invoice
end
@ -208,11 +222,18 @@ class Subscription < ActiveRecord::Base
expiration_date
end
def free_extend(expiration)
def free_extend(expiration, operator_id)
return false if expiration <= expired_at
od = offer_days.create(start_at: expired_at, end_at: expiration)
invoice = Invoice.new(invoiced_id: od.id, invoiced_type: 'OfferDay', invoicing_profile: user.invoicing_profile, total: 0)
invoice = Invoice.new(
invoiced_id: od.id,
invoiced_type: 'OfferDay',
invoicing_profile: user.invoicing_profile,
statistic_profile: user.statistic_profile,
operator_id: operator_id,
total: 0
)
invoice.invoice_items.push InvoiceItem.new(amount: 0, description: plan.name, subscription_id: id)
invoice.save

View File

@ -38,8 +38,6 @@ class User < ActiveRecord::Base
has_many :training_credits, through: :users_credits, source: :training_credit
has_many :machine_credits, through: :users_credits, source: :machine_credit
has_many :operated_invoices, foreign_key: :operator_id, class_name: 'Invoice', dependent: :nullify
has_many :user_tags, dependent: :destroy
has_many :tags, through: :user_tags
accepts_nested_attributes_for :tags, allow_destroy: true
@ -139,16 +137,6 @@ class User < ActiveRecord::Base
Stripe::Customer.retrieve stp_customer_id
end
def soft_destroy
update_attribute(:is_active, false)
uninvolve_from_projects
end
def uninvolve_from_projects
my_projects.destroy_all
project_users.destroy_all
end
def active_for_authentication?
super && is_active?
end

View File

@ -131,14 +131,16 @@ class PDF::Invoice < Prawn::Document
else
subscription_end_at = if subscription_expiration_date.is_a?(Time)
subscription_expiration_date
else
elsif subscription_expiration_date.is_a?(String)
DateTime.parse(subscription_expiration_date)
else
subscription.expiration_date
end
subscription_start_at = subscription_end_at - subscription.plan.duration
details += I18n.t('invoices.subscription_NAME_from_START_to_END',
NAME: item.description,
START: I18n.l(subscription_start_at.to_date),
END: I18n.l(subscription_expiration_date.to_date))
END: I18n.l(subscription_end_at.to_date))
end

View File

@ -30,6 +30,13 @@ class Members::MembersService
# if the user is created by an admin and the authentication is made through an SSO, generate a migration token
@member.generate_auth_migration_token if current_user.admin? && AuthProvider.active.providable_type != DatabaseProvider.name
# setup the attached profiles (invoicing & statistics)
@member.invoicing_profile.email = params[:email]
@member.invoicing_profile.first_name = params[:profile_attributes][:first_name]
@member.invoicing_profile.last_name = params[:profile_attributes][:last_name]
@member.statistic_profile.group_id = params[:group_id]
@member.statistic_profile.role_id = Role.find_by(name: 'member').id
if @member.save
@member.generate_subscription_invoice(current_user.id)
@member.send_confirmation_instructions

View File

@ -21,7 +21,7 @@ class Subscriptions::Subscribe
end
def extend_subscription(subscription, new_expiration_date, free_days)
return subscription.free_extend(new_expiration_date) if free_days
return subscription.free_extend(new_expiration_date, @operator_id) if free_days
new_sub = Subscription.create(
plan_id: subscription.plan_id,

View File

@ -48,8 +48,11 @@ en:
edit_my_profile: "Edit my profile"
your_group_has_been_successfully_changed: "Your group has been successfully changed."
an_unexpected_error_prevented_your_group_from_being_changed: "An unexpected error prevented your group from being changed."
do_you_really_want_to_delete_your_account: "Do you really want to delete your account?"
all_data_relative_to_your_projects_will_be_lost: "All data relative to your projects will be lost."
confirm_delete_your_account: "Do you really want to delete your account?"
all_data_will_be_lost: "All your data will be destroyed and won't be recoverable."
invoicing_data_kept: "According to regulation, all data related to your invoices will be kept separately for 10 years."
statistic_data_anonymized: "Some data (sex, date of birth, group) will be anonymized and kept for statistical purposes."
no_further_access_to_projects: "Your published projects will be anonymized and you won't get any further ability to edit them."
your_user_account_has_been_successfully_deleted_goodbye: "Your user account has been successfully deleted. Goodbye."
an_error_occured_preventing_your_account_from_being_deleted: "An error occurred, preventing your account from being deleted."
projects:

View File

@ -48,8 +48,11 @@ es:
edit_my_profile: "Editar mi perfil"
your_group_has_been_successfully_changed: "Su grupo ha sido cambiado con exito."
an_unexpected_error_prevented_your_group_from_being_changed: "Un error inesperado impidió que su grupo fuese cambiado."
do_you_really_want_to_delete_your_account: "¿Está seguro de querer eliminar su cuenta?"
all_data_relative_to_your_projects_will_be_lost: "Todo dato relacionado con sus proyectos se perderá"
confirm_delete_your_account: "¿Está seguro de querer eliminar su cuenta?"
all_data_will_be_lost: "All your data will be destroyed and won't be recoverable." # missing translation
invoicing_data_kept: "According to regulation, all data related to your invoices will be kept separately for 10 years." # missing translation
statistic_data_anonymized: "Some data (sex, date of birth, group) will be anonymized and kept for statistical purposes." # missing translation
no_further_access_to_projects: "Your published projects will be anonymized and you won't get any further ability to edit them." # missing translation
your_user_account_has_been_successfully_deleted_goodbye: "Su cuenta ha sido eliminada con éxito. Adiós"
an_error_occured_preventing_your_account_from_being_deleted: "Un error inesperado impidió que su cuenta fuese eliminada."
projects:

View File

@ -48,8 +48,11 @@ fr:
edit_my_profile: "Éditer votre profil"
your_group_has_been_successfully_changed: "Votre groupe a bien été changé."
an_unexpected_error_prevented_your_group_from_being_changed: "Une erreur inattendue a empêché votre changement de groupe."
do_you_really_want_to_delete_your_account: "Êtes-vous sûr de vouloir supprimer votre compte ?"
all_data_relative_to_your_projects_will_be_lost: "Toutes les données relatives à vos projets seront détruites."
confirm_delete_your_account: "Êtes-vous sûr de vouloir supprimer votre compte ?"
all_data_will_be_lost: "Toutes vos données seront détruites et ne pourront pas être récupérées."
invoicing_data_kept: "Conformément à la réglementation, les données relatives à vos facturations seront conservées de manière séparée pendant 10 ans."
statistic_data_anonymized: "Certaines données (sexe, date de naissance, groupe) seront anonymisées et conservées à des fins statistiques."
no_further_access_to_projects: "Vos projets publiés seront anonymisés et vous n'aurez plus de possibilité de les modifier."
your_user_account_has_been_successfully_deleted_goodbye: "Votre compte utilisateur a bien été supprimé. Au revoir."
an_error_occured_preventing_your_account_from_being_deleted: "Une erreur est survenue qui a empêché la suppression de votre compte."
projects:

View File

@ -48,8 +48,11 @@ pt:
edit_my_profile: "Editar meu perfil"
your_group_has_been_successfully_changed: "Seu grupo foi modificado com sucesso."
an_unexpected_error_prevented_your_group_from_being_changed: "Um erro inesperado impediu o seu grupo de ser alterado."
do_you_really_want_to_delete_your_account: "Você realmente deseja deletar sua conta?"
all_data_relative_to_your_projects_will_be_lost: "Todos os dados relativos aos seus projectos serão perdidos."
confirm_delete_your_account: "Você realmente deseja deletar sua conta?"
all_data_will_be_lost: "All your data will be destroyed and won't be recoverable." # missing translation
invoicing_data_kept: "According to regulation, all data related to your invoices will be kept separately for 10 years." # missing translation
statistic_data_anonymized: "Some data (sex, date of birth, group) will be anonymized and kept for statistical purposes." # missing translation
no_further_access_to_projects: "Your published projects will be anonymized and you won't get any further ability to edit them." # missing translation
your_user_account_has_been_successfully_deleted_goodbye: "Sua conta de usuário foi excluída com êxito. Até mais."
an_error_occured_preventing_your_account_from_being_deleted: "Ocorreu um erro, impedindo que sua conta fosse excluída."
projects:
@ -98,19 +101,19 @@ pt:
machines_reserve:
# book a machine
machine_planning: "Planejamento de máquinas"
i_ve_reserved: "Eu tenho reserva"
i_ve_reserved: "Eu tenho reserva"
not_available: "Não disponível"
i_reserve: "Eu reservo"
i_shift: "Eu mudo"
i_change: "Eu altero"
trainings_reserve:
# book a training
trainings_planning: "Planos de treinamento"
planning_of: "Planejamento de" # followed by the training name (eg. "Planning of 3d printer training")
all_trainings: "Todos treinamentos"
cancel_my_selection: "Cancelar minha seleção"
i_ve_reserved: "Eu reservei"
cancel_my_selection: "Cancelar minha seleção"
i_ve_reserved: "Eu reservei"
space_reserve:
# book a space
@ -118,7 +121,7 @@ pt:
planning_of_space_NAME: "Plano de {{NAME}} espaço" # angular interpolation
i_ve_reserved: "Eu reservei"
i_shift: "Eu troco"
i_change: "Eu altero"
i_change: "Eu altero"
notifications:
notifications_center: "Centro de notificações"

View File

@ -9,8 +9,8 @@ namespace :fablab do
month = args.month || Time.now.month
start_date = Time.new(year.to_i, month.to_i, 1)
end_date = start_date.next_month
puts "-> Start regenerate the invoices PDF between #{I18n.l start_date, format: :long} in " \
" #{I18n.l end_date - 1.minute, format: :long}"
puts "-> Start regenerate the invoices PDF between #{I18n.l start_date, format: :long} and " \
"#{I18n.l end_date - 1.minute, format: :long}"
invoices = Invoice.only_invoice
.where('created_at >= :start_date AND created_at < :end_date', start_date: start_date, end_date: end_date)
.order(created_at: :asc)

View File

@ -79,5 +79,22 @@ namespace :fablab do
)
end
end
desc 'migrate invoices PDF to folders by invoicing_profile'
task migrate_invoices_pdf_folders: :environment do
require 'fileutils'
Invoice.all.each do |i|
invoicing_profile = i.invoicing_profile
user_id = invoicing_profile.user_id
src = "invoices/#{user_id}/#{i.filename}"
dest = "tmp/invoices/#{invoicing_profile.id}"
FileUtils.mkdir_p dest
FileUtils.mv src, "dest/#{i.filename}", force: true if FileTest.exist?(src)
end
FileUtils.rm_rf 'invoices'
FileUtils.mv 'tmp/invoices', 'invoices'
end
end
end