1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-11-29 10:24:20 +01:00

check server-side that periods match length requirements + explain requirements to user before closing

This commit is contained in:
Sylvain 2019-04-03 13:04:19 +02:00
parent 93ff761e64
commit 722d5d36e7
12 changed files with 81 additions and 9 deletions

View File

@ -676,8 +676,8 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
/**
* Controller used in the modal window allowing an admin to close an accounting period
*/
Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$uibModalInstance', '$window', 'Invoice', 'AccountingPeriod', 'periods', 'lastClosingEnd','dialogs', 'growl', '_t',
function ($scope, $uibModalInstance, $window, Invoice, AccountingPeriod, periods, lastClosingEnd, dialogs, growl, _t) {
Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$uibModalInstance', '$window', '$sce', 'Invoice', 'AccountingPeriod', 'periods', 'lastClosingEnd','dialogs', 'growl', '_t',
function ($scope, $uibModalInstance, $window, $sce, Invoice, AccountingPeriod, periods, lastClosingEnd, dialogs, growl, _t) {
const YESTERDAY = moment.utc({ h: 0, m: 0, s: 0, ms: 0 }).subtract(1, 'day').toDate();
const LAST_CLOSING = moment.utc(lastClosingEnd.last_end_date).toDate();
const MAX_END = moment.utc(lastClosingEnd.last_end_date).add(1, 'year').subtract(1, 'day').toDate();
@ -734,9 +734,15 @@ Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$ui
object () {
return {
title: _t('invoices.confirmation_required'),
msg: _t(
'invoices.confirm_close_START_END',
{ START: moment.utc($scope.period.start_at).format('LL'), END: moment.utc($scope.period.end_at).format('LL') }
msg: $sce.trustAsHtml(
_t(
'invoices.confirm_close_START_END',
{ START: moment.utc($scope.period.start_at).format('LL'), END: moment.utc($scope.period.end_at).format('LL') }
)
+ '<br/><br/><strong>'
+ _t('invoices.period_must_match_fiscal_year')
+ '</strong><br/><br/>'
+ _t('invoices.this_may_take_a_while')
)
};
}

View File

@ -14,6 +14,7 @@ class AccountingPeriod < ActiveRecord::Base
validates :start_at, :end_at, :closed_at, :closed_by, presence: true
validates_with DateRangeValidator
validates_with DurationValidator
validates_with PeriodOverlapValidator
validates_with PeriodIntegrityValidator

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
# Validates that the duration between start_at and end_at is between 1 day and 1 year
class DurationValidator < ActiveModel::Validator
def validate(record)
the_end = record.end_at
the_start = record.start_at
diff = (the_end - the_start).to_i
return if diff.days >= 1.day && diff.days <= 1.year
record.errors[:end_at] << I18n.t('errors.messages.invalid_duration', DAYS: diff)
end
end

View File

@ -421,7 +421,9 @@ en:
perpetual_total: "Perpetual total"
integrity: "Integrity check"
confirmation_required: "Confirmation required"
confirm_close_START_END: "Do you really want to close the accounting period between {{START}} and {{END}}? Any subsequent changes will be impossible. This operation will take some time to complete"
confirm_close_START_END: "Do you really want to close the accounting period between {{START}} and {{END}}? Any subsequent changes will be impossible."
period_must_match_fiscal_year: "A closing must occur at the end of a minimum annual period, or per financial year when it is not calendar-based."
this_may_take_a_while: "This operation will take some time to complete."
period_START_END_closed_success: "The accounting period from {{START}} to {{END}} has been successfully closed"
failed_to_close_period: "An error occurred, unable to close the accounting period"
no_periods: "No closings for now"

View File

@ -421,7 +421,9 @@ es:
perpetual_total: "Perpetual total" # translation_missing
integrity: "Verificación de integridad"
confirmation_required: "Confirmation required" # translation_missing
confirm_close_START_END: "Do you really want to close the accounting period between {{START}} and {{END}}? Any subsequent changes will be impossible. This operation will take some time to complete" # translation_missing
confirm_close_START_END: "Do you really want to close the accounting period between {{START}} and {{END}}? Any subsequent changes will be impossible." # translation_missing
period_must_match_fiscal_year: "A closing must occur at the end of a minimum annual period, or per financial year when it is not calendar-based." # translation_missing
this_may_take_a_while: "This operation will take some time to complete." # translation_missing
period_START_END_closed_success: "The accounting period from {{START}} to {{END}} has been successfully closed" # translation_missing
failed_to_close_period: "An error occurred, unable to close the accounting period" # translation_missing
no_periods: "No closings for now" # translation_missing

View File

@ -421,7 +421,9 @@ fr:
perpetual_total: "Total perpétuel"
integrity: "Contrôle d'intégrité"
confirmation_required: "Confirmation requise"
confirm_close_START_END: "Êtes-vous sur de vouloir clôturer la période comptable du {{START}} au {{END}} ? Toute modification ultérieure sera impossible. Cette opération va prendre un certain temps."
confirm_close_START_END: "Êtes-vous sur de vouloir clôturer la période comptable du {{START}} au {{END}} ? Toute modification ultérieure sera impossible."
period_must_match_fiscal_year: "Une clôture doit intervenir à l'issue d'une période au minimum annuelle, ou par exercice lorsque celui-ci n'est pas calé sur l'année civile."
this_may_take_a_while: "Cette opération va prendre un certain temps."
period_START_END_closed_success: "La période comptable du {{START}} au {{END}} a bien été clôturée"
failed_to_close_period: "Une erreur est survenue, impossible de clôturer la période comptable"
no_periods: "Aucune clôture pour le moment"

View File

@ -421,7 +421,9 @@ pt:
perpetual_total: "Perpetual total" # translation_missing
integrity: "Verificação de integridade"
confirmation_required: "Confirmation required" # translation_missing
confirm_close_START_END: "Do you really want to close the accounting period between {{START}} and {{END}}? Any subsequent changes will be impossible. This operation will take some time to complete." # translation_missing
confirm_close_START_END: "Do you really want to close the accounting period between {{START}} and {{END}}? Any subsequent changes will be impossible" # translation_missing
period_must_match_fiscal_year: "A closing must occur at the end of a minimum annual period, or per financial year when it is not calendar-based." # translation_missing
this_may_take_a_while: "This operation will take some time to complete." # translation_missing
period_START_END_closed_success: "The accounting period from {{START}} to {{END}} has been successfully closed" # translation_missing
failed_to_close_period: "An error occurred, unable to close the accounting period" # translation_missing
no_periods: "No closings for now" # translation_missing

View File

@ -41,6 +41,7 @@ en:
in_closed_period: "can't be within a closed accounting period"
invalid_footprint: "invoice's checksum is invalid"
end_before_start: "The end date can't be before the start date. Pick a date after %{START}"
invalid_duration: "The allowed duration must be between 1 day and 1 year. Your period is %{DAYS} days long."
activemodel:
errors:

View File

@ -41,6 +41,7 @@ es:
in_closed_period: "can't be within a closed accounting period" # missing translation
invalid_footprint: "invoice's checksum is invalid" # missing translation
end_before_start: "The end date can't be before the start date. Pick a date after %{START}" # missing translation
invalid_duration: "The allowed duration must be between 1 day and 1 year. Your period is %{DAYS} days long." # missing translation
activemodel:
errors:

View File

@ -41,6 +41,7 @@ fr:
in_closed_period: "ne peut pas être dans une période comptable fermée"
invalid_footprint: "la somme de contrôle de la facture est invalide"
end_before_start: "La date de fin ne peut pas être antérieure à la date de début. Choisissez une date après le %{START}"
invalid_duration: "La durée doit être comprise entre 1 jour et 1 an. Votre période dure %{DAYS} jours."
activemodel:
errors:

View File

@ -41,6 +41,7 @@ pt:
in_closed_period: "can't be within a closed accounting period" # missing translation
invalid_footprint: "invoice's checksum is invalid" # missing translation
end_before_start: "The end date can't be before the start date. Pick a date after %{START}" # missing translation
invalid_duration: "The allowed duration must be between 1 day and 1 year. Your period is %{DAYS} days long." # missing translation
activemodel:
errors:

View File

@ -68,4 +68,44 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest
FileUtils.rm_rf(accounting_period.archive_folder)
end
test 'admin tries to closes a too long period' do
start_at = '2012-01-01T00:00:00.000Z'
end_at = '2014-12-31T00:00:00.000Z'
diff = (end_at.to_date - start_at.to_date).to_i
post '/api/accounting_periods',
{
accounting_period: {
start_at: start_at,
end_at: end_at
}
}.to_json, default_headers
# Check response format & status
assert_equal 422, response.status, response.body
assert_equal Mime::JSON, response.content_type
# check the error
assert_match(/#{I18n.t('errors.messages.invalid_duration', DAYS: diff)}/, response.body)
end
test 'admin tries to closes an overlapping period' do
start_at = '2014-12-01T00:00:00.000Z'
end_at = '2015-02-27T00:00:00.000Z'
post '/api/accounting_periods',
{
accounting_period: {
start_at: start_at,
end_at: end_at
}
}.to_json, default_headers
# Check response format & status
assert_equal 422, response.status, response.body
assert_equal Mime::JSON, response.content_type
# check the error
assert_match(/#{I18n.t('errors.messages.cannot_overlap')}/, response.body)
end
end