mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-17 06:52:27 +01:00
Merge branch 'us78' into host
This commit is contained in:
commit
79ad9ce8e2
2
.gitignore
vendored
2
.gitignore
vendored
@ -34,6 +34,8 @@
|
||||
# XLSX exports
|
||||
/exports/*
|
||||
|
||||
# Archives of cLosed accounting periods
|
||||
/accounting/*
|
||||
|
||||
.DS_Store
|
||||
|
||||
|
@ -7,10 +7,14 @@ Metrics/CyclomaticComplexity:
|
||||
Metrics/PerceivedComplexity:
|
||||
Max: 9
|
||||
Metrics/AbcSize:
|
||||
Max: 42
|
||||
Max: 45
|
||||
Style/BracesAroundHashParameters:
|
||||
EnforcedStyle: context_dependent
|
||||
Style/RegexpLiteral:
|
||||
EnforcedStyle: slashes
|
||||
Style/EmptyElse:
|
||||
EnforcedStyle: empty
|
||||
Style/ClassAndModuleChildren:
|
||||
EnforcedStyle: compact
|
||||
Style/AndOr:
|
||||
EnforcedStyle: conditionals
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
- Fix a bug: error handling on password recovery
|
||||
- Fix a bug: error handling on machine attachment upload
|
||||
- Fix a bug: first day of week is ignored in statistics custom filter
|
||||
- Fix a bug: rails DSB locale is invalid
|
||||
- Refactored frontend invoices translations
|
||||
|
||||
## v2.8.1 2019 January 02
|
||||
|
||||
|
@ -44,6 +44,7 @@ RUN mkdir -p /usr/src/app/exports
|
||||
RUN mkdir -p /usr/src/app/log
|
||||
RUN mkdir -p /usr/src/app/public/uploads
|
||||
RUN mkdir -p /usr/src/app/public/assets
|
||||
RUN mkdir -p /usr/src/app/accounting
|
||||
RUN mkdir -p /usr/src/app/tmp/sockets
|
||||
RUN mkdir -p /usr/src/app/tmp/pids
|
||||
|
||||
@ -64,6 +65,7 @@ VOLUME /usr/src/app/exports
|
||||
VOLUME /usr/src/app/public
|
||||
VOLUME /usr/src/app/public/uploads
|
||||
VOLUME /usr/src/app/public/assets
|
||||
VOLUME /usr/src/app/accounting
|
||||
VOLUME /var/log/supervisor
|
||||
|
||||
# Expose port 3000 to the Docker host, so we can access it
|
||||
|
@ -332,6 +332,7 @@ This can be achieved doing the following:
|
||||
- `db/migrate/20150604131525_add_meta_data_to_notifications.rb` is using [jsonb](https://www.postgresql.org/docs/9.4/static/datatype-json.html), a PostgreSQL 9.4+ datatype.
|
||||
- `db/migrate/20160915105234_add_transformation_to_o_auth2_mapping.rb` is using [jsonb](https://www.postgresql.org/docs/9.4/static/datatype-json.html), a PostgreSQL 9.4+ datatype.
|
||||
- `db/migrate/20181217103441_migrate_settings_value_to_history_values.rb` is using `SELECT DISTINCT ON`.
|
||||
- `db/migrate/20190107111749_protect_accounting_periods.rb` is using `CREATE RULE` and `DROP RULE`.
|
||||
- If you intend to contribute to the project code, you will need to run the test suite with `rake test`.
|
||||
This also requires your user to have the _SUPERUSER_ role.
|
||||
Please see the [known issues](#known-issues) section for more information about this.
|
||||
|
@ -17,8 +17,8 @@
|
||||
/**
|
||||
* Controller used in the admin invoices listing page
|
||||
*/
|
||||
Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'Invoice', 'invoices', '$uibModal', 'growl', '$filter', 'Setting', 'settings', '_t',
|
||||
function ($scope, $state, Invoice, invoices, $uibModal, growl, $filter, Setting, settings, _t) {
|
||||
Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'Invoice', 'AccountingPeriod', 'invoices', 'closedPeriods', '$uibModal', 'growl', '$filter', 'Setting', 'settings', '_t',
|
||||
function ($scope, $state, Invoice, AccountingPeriod, invoices, closedPeriods, $uibModal, growl, $filter, Setting, settings, _t) {
|
||||
/* PRIVATE STATIC CONSTANTS */
|
||||
|
||||
// number of invoices loaded each time we click on 'load more...'
|
||||
@ -105,12 +105,13 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
* @param invoice {Object} invoice inherited from angular's $resource
|
||||
*/
|
||||
$scope.generateAvoirForInvoice = function (invoice) {
|
||||
// open modal
|
||||
// open modal
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/invoices/avoirModal.html" %>',
|
||||
controller: 'AvoirModalController',
|
||||
resolve: {
|
||||
invoice () { return invoice; }
|
||||
invoice () { return invoice; },
|
||||
closedPeriods() { return AccountingPeriod.query().$promise; }
|
||||
}
|
||||
});
|
||||
|
||||
@ -119,7 +120,7 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
$scope.invoices.unshift(res.avoir);
|
||||
return Invoice.get({ id: invoice.id }, function (data) {
|
||||
invoice.has_avoir = data.has_avoir;
|
||||
return growl.success(_t('refund_invoice_successfully_created'));
|
||||
return growl.success(_t('invoices.refund_invoice_successfully_created'));
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -193,10 +194,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
modalInstance.result.then(function (model) {
|
||||
Setting.update({ name: 'invoice_reference' }, { value: model }, function (data) {
|
||||
$scope.invoice.reference.model = model;
|
||||
growl.success(_t('invoice_reference_successfully_saved'));
|
||||
growl.success(_t('invoices.invoice_reference_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
growl.error(_t('an_error_occurred_while_saving_invoice_reference'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_saving_invoice_reference'));
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
@ -231,24 +232,24 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
Setting.update({ name: 'invoice_code-value' }, { value: result.model }, function (data) {
|
||||
$scope.invoice.code.model = result.model;
|
||||
if (result.active) {
|
||||
return growl.success(_t('invoicing_code_succesfully_saved'));
|
||||
return growl.success(_t('invoices.invoicing_code_succesfully_saved'));
|
||||
}
|
||||
}
|
||||
, function (error) {
|
||||
growl.error(_t('an_error_occurred_while_saving_the_invoicing_code'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_saving_the_invoicing_code'));
|
||||
return console.error(error);
|
||||
});
|
||||
|
||||
return Setting.update({ name: 'invoice_code-active' }, { value: result.active ? 'true' : 'false' }, function (data) {
|
||||
$scope.invoice.code.active = result.active;
|
||||
if (result.active) {
|
||||
return growl.success(_t('code_successfully_activated'));
|
||||
return growl.success(_t('invoices.code_successfully_activated'));
|
||||
} else {
|
||||
return growl.success(_t('code_successfully_disabled'));
|
||||
return growl.success(_t('invoices.code_successfully_disabled'));
|
||||
}
|
||||
}
|
||||
, function (error) {
|
||||
growl.error(_t('an_error_occurred_while_activating_the_invoicing_code'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_activating_the_invoicing_code'));
|
||||
return console.error(error);
|
||||
});
|
||||
});
|
||||
@ -277,10 +278,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
return modalInstance.result.then(function (model) {
|
||||
Setting.update({ name: 'invoice_order-nb' }, { value: model }, function (data) {
|
||||
$scope.invoice.number.model = model;
|
||||
return growl.success(_t('order_number_successfully_saved'));
|
||||
return growl.success(_t('invoices.order_number_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
growl.error(_t('an_error_occurred_while_saving_the_order_number'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_saving_the_order_number'));
|
||||
return console.error(error);
|
||||
});
|
||||
});
|
||||
@ -316,24 +317,24 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
Setting.update({ name: 'invoice_VAT-rate' }, { value: result.rate + '' }, function (data) {
|
||||
$scope.invoice.VAT.rate = result.rate;
|
||||
if (result.active) {
|
||||
return growl.success(_t('VAT_rate_successfully_saved'));
|
||||
return growl.success(_t('invoices.VAT_rate_successfully_saved'));
|
||||
}
|
||||
}
|
||||
, function (error) {
|
||||
growl.error(_t('an_error_occurred_while_saving_the_VAT_rate'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_saving_the_VAT_rate'));
|
||||
return console.error(error);
|
||||
});
|
||||
|
||||
return Setting.update({ name: 'invoice_VAT-active' }, { value: result.active ? 'true' : 'false' }, function (data) {
|
||||
$scope.invoice.VAT.active = result.active;
|
||||
if (result.active) {
|
||||
return growl.success(_t('VAT_successfully_activated'));
|
||||
return growl.success(_t('invoices.VAT_successfully_activated'));
|
||||
} else {
|
||||
return growl.success(_t('VAT_successfully_disabled'));
|
||||
return growl.success(_t('invoices.VAT_successfully_disabled'));
|
||||
}
|
||||
}
|
||||
, function (error) {
|
||||
growl.error(_t('an_error_occurred_while_activating_the_VAT'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_activating_the_VAT'));
|
||||
return console.error(error);
|
||||
});
|
||||
});
|
||||
@ -346,10 +347,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
const parsed = parseHtml($scope.invoice.text.content);
|
||||
return Setting.update({ name: 'invoice_text' }, { value: parsed }, function (data) {
|
||||
$scope.invoice.text.content = parsed;
|
||||
return growl.success(_t('text_successfully_saved'));
|
||||
return growl.success(_t('invoices.text_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
growl.error(_t('an_error_occurred_while_saving_the_text'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_saving_the_text'));
|
||||
return console.error(error);
|
||||
});
|
||||
};
|
||||
@ -361,10 +362,10 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
const parsed = parseHtml($scope.invoice.legals.content);
|
||||
return Setting.update({ name: 'invoice_legals' }, { value: parsed }, function (data) {
|
||||
$scope.invoice.legals.content = parsed;
|
||||
return growl.success(_t('address_and_legal_information_successfully_saved'));
|
||||
return growl.success(_t('invoices.address_and_legal_information_successfully_saved'));
|
||||
}
|
||||
, function (error) {
|
||||
growl.error(_t('an_error_occurred_while_saving_the_address_and_the_legal_information'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_saving_the_address_and_the_legal_information'));
|
||||
return console.error(error);
|
||||
});
|
||||
};
|
||||
@ -387,6 +388,37 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
return invoiceSearch(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Open a modal allowing the user to close an accounting period and to
|
||||
* view all periods already closed.
|
||||
*/
|
||||
$scope.closeAnAccountingPeriod = function() {
|
||||
// open modal
|
||||
$uibModal.open({
|
||||
templateUrl: '<%= asset_path "admin/invoices/closePeriodModal.html" %>',
|
||||
controller: 'ClosePeriodModalController',
|
||||
size: 'lg',
|
||||
resolve: {
|
||||
periods() { return AccountingPeriod.query().$promise; },
|
||||
lastClosingEnd() { return AccountingPeriod.lastClosingEnd().$promise; },
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the given date is within a closed accounting period
|
||||
* @param date {Date} date to test
|
||||
* @returns {boolean} true if closed, false otherwise
|
||||
*/
|
||||
$scope.isDateClosed = function(date) {
|
||||
for (const period of closedPeriods) {
|
||||
if (moment(date).isBetween(moment.utc(period.start_at).startOf('day'), moment.utc(period.end_at).endOf('day'), null, '[]')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/**
|
||||
@ -418,9 +450,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
return Setting.update(
|
||||
{ name: 'invoice_logo' },
|
||||
{ value: $scope.invoice.logo.base64 },
|
||||
function (data) { growl.success(_t('logo_successfully_saved')); },
|
||||
function (data) { growl.success(_t('invoices.logo_successfully_saved')); },
|
||||
function (error) {
|
||||
growl.error(_t('an_error_occurred_while_saving_the_logo'));
|
||||
growl.error(_t('invoices.an_error_occurred_while_saving_the_logo'));
|
||||
return console.error(error);
|
||||
}
|
||||
);
|
||||
@ -496,9 +528,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
/**
|
||||
* Controller used in the invoice refunding modal window
|
||||
*/
|
||||
Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModalInstance', 'invoice', 'Invoice', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, invoice, Invoice, growl, _t) {
|
||||
/* PUBLIC SCOPE */
|
||||
Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModalInstance', 'invoice', 'closedPeriods', 'Invoice', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, invoice, closedPeriods, Invoice, growl, _t) {
|
||||
/* PUBLIC SCOPE */
|
||||
|
||||
// invoice linked to the current refund
|
||||
$scope.invoice = invoice;
|
||||
@ -515,11 +547,11 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
|
||||
// Possible refunding methods
|
||||
$scope.avoirModes = [
|
||||
{ name: _t('none'), value: 'none' },
|
||||
{ name: _t('by_cash'), value: 'cash' },
|
||||
{ name: _t('by_cheque'), value: 'cheque' },
|
||||
{ name: _t('by_transfer'), value: 'transfer' },
|
||||
{ name: _t('by_wallet'), value: 'wallet' }
|
||||
{ name: _t('invoices.none'), value: 'none' },
|
||||
{ name: _t('invoices.by_cash'), value: 'cash' },
|
||||
{ name: _t('invoices.by_cheque'), value: 'cheque' },
|
||||
{ name: _t('invoices.by_transfer'), value: 'transfer' },
|
||||
{ name: _t('invoices.by_wallet'), value: 'wallet' }
|
||||
];
|
||||
|
||||
// If a subscription was took with the current invoice, should it be canceled or not
|
||||
@ -542,14 +574,14 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
$scope.openDatePicker = function ($event) {
|
||||
$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
return $scope.datePicker.opened = true;
|
||||
$scope.datePicker.opened = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate the refunding and generate a refund invoice
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
// check that at least 1 element of the invoice is refunded
|
||||
// check that at least 1 element of the invoice is refunded
|
||||
$scope.avoir.invoice_items_ids = [];
|
||||
for (let itemId in $scope.partial) {
|
||||
const refundItem = $scope.partial[itemId];
|
||||
@ -557,7 +589,7 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
}
|
||||
|
||||
if ($scope.avoir.invoice_items_ids.length === 0) {
|
||||
return growl.error(_t('you_must_select_at_least_one_element_to_create_a_refund'));
|
||||
return growl.error(_t('invoices.you_must_select_at_least_one_element_to_create_a_refund'));
|
||||
} else {
|
||||
return Invoice.save(
|
||||
{ avoir: $scope.avoir },
|
||||
@ -565,17 +597,31 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
$uibModalInstance.close({ avoir, invoice: $scope.invoice });
|
||||
},
|
||||
function (err) { // failed
|
||||
growl.error(_t('unable_to_create_the_refund'));
|
||||
growl.error(_t('invoices.unable_to_create_the_refund'));
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**q
|
||||
/**
|
||||
* Cancel the refund, dismiss the modal window
|
||||
*/
|
||||
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
|
||||
/**
|
||||
* Test if the given date is within a closed accounting period
|
||||
* @param date {Date} date to test
|
||||
* @returns {boolean} true if closed, false otherwise
|
||||
*/
|
||||
$scope.isDateClosed = function(date) {
|
||||
for (const period of closedPeriods) {
|
||||
if (moment(date).isBetween(moment.utc(period.start_at).startOf('day'), moment.utc(period.end_at).endOf('day'), null, '[]')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/**
|
||||
@ -592,7 +638,7 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
});
|
||||
|
||||
if (invoice.stripe) {
|
||||
return $scope.avoirModes.push({ name: _t('online_payment'), value: 'stripe' });
|
||||
return $scope.avoirModes.push({ name: _t('invoices.online_payment'), value: 'stripe' });
|
||||
}
|
||||
};
|
||||
|
||||
@ -600,3 +646,90 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
|
||||
return initialize();
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* Controller used in the modal window allowing an admin to close an accounting period
|
||||
*/
|
||||
Application.Controllers.controller('ClosePeriodModalController', ['$scope', '$uibModalInstance', 'Invoice', 'AccountingPeriod', 'periods', 'lastClosingEnd','dialogs', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, 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();
|
||||
|
||||
/* PUBLIC SCOPE */
|
||||
|
||||
// date pickers values are bound to these variables
|
||||
$scope.period = {
|
||||
start_at: LAST_CLOSING,
|
||||
end_at: YESTERDAY
|
||||
};
|
||||
|
||||
// any form errors will come here
|
||||
$scope.errors = {};
|
||||
|
||||
// existing closed periods, provided by the API
|
||||
$scope.accountingPeriods = periods;
|
||||
|
||||
// AngularUI-Bootstrap datepickers parameters to define the period to close
|
||||
$scope.datePicker = {
|
||||
format: Fablab.uibDateFormat,
|
||||
// default: datePicker are not shown
|
||||
startOpened: false,
|
||||
endOpened: false,
|
||||
minDate: LAST_CLOSING,
|
||||
maxDate: YESTERDAY,
|
||||
options: {
|
||||
startingDay: Fablab.weekStartingDay
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback to open the datepicker
|
||||
*/
|
||||
$scope.openDatePicker = function ($event, pickerId) {
|
||||
$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
$scope.datePicker[`${pickerId}Opened`] = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate the close period creation
|
||||
*/
|
||||
$scope.ok = function () {
|
||||
dialogs.confirm(
|
||||
{
|
||||
resolve: {
|
||||
object () {
|
||||
return {
|
||||
title: _t('invoices.confirmation_required'),
|
||||
msg: _t(
|
||||
'invoices.confirm_close_START_END',
|
||||
{ START: moment($scope.period.start_at).format('LL'), END: moment($scope.period.end_at).format('LL') }
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
function () { // creation confirmed
|
||||
AccountingPeriod.save({ accounting_period: $scope.period }, function (resp) {
|
||||
growl.success(_t(
|
||||
'invoices.period_START_END_closed_success',
|
||||
{ START: moment(resp.start_at).format('LL'), END: moment(resp.end_at).format('LL') }
|
||||
));
|
||||
$uibModalInstance.close(resp);
|
||||
}
|
||||
, function(error) {
|
||||
growl.error(_t('invoices.failed_to_close_period'));
|
||||
$scope.errors = error.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel the refund, dismiss the modal window
|
||||
*/
|
||||
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
}
|
||||
]);
|
||||
|
@ -94,9 +94,9 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
|
||||
minDate: null,
|
||||
maxDate: moment().toDate(),
|
||||
options: {
|
||||
startingDay: 1
|
||||
startingDay: Fablab.weekStartingDay
|
||||
}
|
||||
} // France: the week starts on monday
|
||||
}
|
||||
};
|
||||
|
||||
// available custom filters
|
||||
|
@ -885,6 +885,7 @@ angular.module('application.router', ['ui.router'])
|
||||
query: { number: '', customer: '', date: null, order_by: '-reference', page: 1, size: 20 }
|
||||
}).$promise;
|
||||
}],
|
||||
closedPeriods: [ 'AccountingPeriod', function(AccountingPeriod) { return AccountingPeriod.query().$promise; }],
|
||||
translations: ['Translations', function (Translations) { return Translations.query('app.admin.invoices').$promise; }]
|
||||
}
|
||||
})
|
||||
|
12
app/assets/javascripts/services/accounting_period.js
Normal file
12
app/assets/javascripts/services/accounting_period.js
Normal file
@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
Application.Services.factory('AccountingPeriod', ['$resource', function ($resource) {
|
||||
return $resource('/api/accounting_periods/:id',
|
||||
{ id: '@id' }, {
|
||||
lastClosingEnd: {
|
||||
method: 'GET',
|
||||
url: '/api/accounting_periods/last_closing_end'
|
||||
}
|
||||
}
|
||||
);
|
||||
}]);
|
@ -616,4 +616,8 @@ padding: 10px;
|
||||
& > i.fileinput-exists {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.help-block.error {
|
||||
color: #ff565d;
|
||||
}
|
||||
|
@ -178,4 +178,42 @@
|
||||
border-radius: 5px;
|
||||
font-size: small;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table.closings-table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
|
||||
thead, tbody, tr, th, td { display: block; }
|
||||
|
||||
thead tr {
|
||||
/* fallback */
|
||||
width: 97%;
|
||||
/* minus scroll bar width */
|
||||
width: -webkit-calc(100% - 16px);
|
||||
width: -moz-calc(100% - 16px);
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
|
||||
thead tr th {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
tr:after { /* clearing float */
|
||||
content: ' ';
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
tbody {
|
||||
height: 200px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
tbody td, thead th {
|
||||
width: 24%; /* 24% is less than (100% / 4 cols) = 25% */
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="text-center red" translate>{{ 'create_a_refund_on_this_invoice' }}</h3>
|
||||
<h3 class="text-center red" translate>{{ 'invoices.create_a_refund_on_this_invoice' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form name="avoirForm" novalidate="novalidate">
|
||||
<div class="form-group" ng-class="{'has-error': avoirForm.avoir_date.$dirty && avoirForm.avoir_date.$invalid }">
|
||||
<label translate>{{ 'creation_date_for_the_refund' }}</label>
|
||||
<label translate>{{ 'invoices.creation_date_for_the_refund' }}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
<input type="text"
|
||||
@ -14,28 +14,29 @@
|
||||
uib-datepicker-popup="{{datePicker.format}}"
|
||||
datepicker-options="datePicker.options"
|
||||
is-open="datePicker.opened"
|
||||
date-disabled="isDateClosed(date, mode)"
|
||||
placeholder="{{datePicker.format}}"
|
||||
ng-click="openDatePicker($event)"
|
||||
required/>
|
||||
</div>
|
||||
<span class="help-block" ng-show="avoirForm.avoir_date.$dirty && avoirForm.avoir_date.$error.required" translate>{{ 'creation_date_is_required' }}</span>
|
||||
<span class="help-block" ng-show="avoirForm.avoir_date.$dirty && avoirForm.avoir_date.$error.required" translate>{{ 'invoices.creation_date_is_required' }}</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label translate>{{ 'refund_mode' }}</label>
|
||||
<label translate>{{ 'invoices.refund_mode' }}</label>
|
||||
<select class="form-control m-t-sm" name="avoir_mode" ng-model="avoir.avoir_mode" ng-options="mode.value as mode.name for mode in avoirModes" required></select>
|
||||
</div>
|
||||
<div class="form-group" ng-if="invoice.is_subscription_invoice">
|
||||
<label translate>{{ 'do_you_want_to_disable_the_user_s_subscription' }}</label>
|
||||
<label translate>{{ 'invoices.do_you_want_to_disable_the_user_s_subscription' }}</label>
|
||||
<select class="form-control m-t-sm" name="subscription_to_expire" ng-model="avoir.subscription_to_expire" ng-options="value as key for (key, value) in subscriptionExpireOptions" required></select>
|
||||
</div>
|
||||
<div ng-show="!invoice.is_subscription_invoice && invoice.items.length > 1" class="form-group">
|
||||
<label translate>{{ 'elements_to_refund' }}</label>
|
||||
<label translate>{{ 'invoices.elements_to_refund' }}</label>
|
||||
<table class="table partial-avoir-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="input-col"></th>
|
||||
<th class="label-col" translate>{{ 'description' }}</th>
|
||||
<th class="amount-col" translate>{{ 'price' }}</th>
|
||||
<th class="label-col" translate>{{ 'invoices.description' }}</th>
|
||||
<th class="amount-col" translate>{{ 'invoices.price' }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -48,8 +49,8 @@
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<label for="description" translate>{{ 'description_(optional)' }}</label>
|
||||
<p translate>{{ 'will_appear_on_the_refund_invoice' }}</p>
|
||||
<label for="description" translate>{{ 'invoices.description_(optional)' }}</label>
|
||||
<p translate>{{ 'invoices.will_appear_on_the_refund_invoice' }}</p>
|
||||
<textarea class="form-control m-t-sm" name="description" ng-model="avoir.description"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
@ -57,4 +58,4 @@
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-click="ok()" ng-disabled="avoirForm.$invalid" translate>{{ 'confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'cancel' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,75 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="text-center red" translate>{{ 'invoices.close_accounting_period' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form name="closePeriodForm" novalidate="novalidate" class="row">
|
||||
<div class="form-group col-md-6" ng-class="{'has-error': closePeriodForm.start_at.$dirty && closePeriodForm.start_at.$invalid }">
|
||||
<label translate>{{ 'invoices.close_from_date' }}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="start_at"
|
||||
ng-model="period.start_at"
|
||||
uib-datepicker-popup="{{datePicker.format}}"
|
||||
datepicker-options="datePicker.options"
|
||||
is-open="datePicker.startOpened"
|
||||
min-date="datePicker.minDate"
|
||||
max-date="datePicker.maxDate"
|
||||
init-date="period.start_at"
|
||||
placeholder="{{datePicker.format}}"
|
||||
ng-click="openDatePicker($event, 'start')"
|
||||
required/>
|
||||
</div>
|
||||
<span class="help-block" ng-show="closePeriodForm.start_at.$dirty && closePeriodForm.start_at.$error.required" translate>{{ 'invoices.start_date_is_required' }}</span>
|
||||
<span class="help-block error" ng-show="errors.start_at">{{ errors.start_at[0] }}</span>
|
||||
</div>
|
||||
<div class="form-group col-md-6" ng-class="{'has-error': closePeriodForm.end_at.$dirty && closePeriodForm.end_at.$invalid }">
|
||||
<label translate>{{ 'invoices.close_until_date' }}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="end_at"
|
||||
ng-model="period.end_at"
|
||||
uib-datepicker-popup="{{datePicker.format}}"
|
||||
datepicker-options="datePicker.options"
|
||||
is-open="datePicker.endOpened"
|
||||
min-date="datePicker.minDate"
|
||||
max-date="datePicker.maxDate"
|
||||
init-date="period.end_at"
|
||||
placeholder="{{datePicker.format}}"
|
||||
ng-click="openDatePicker($event, 'end')"
|
||||
required/>
|
||||
</div>
|
||||
<span class="help-block" ng-show="closePeriodForm.end_at.$dirty && closePeriodForm.end_at.$error.required" translate>{{ 'invoices.end_date_is_required' }}</span>
|
||||
<span class="help-block error" ng-show="errors.end_at">{{ errors.end_at[0] }}</span>
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<h4 translate>{{ 'invoices.previous_closings' }}</h4>
|
||||
<table class="table closings-table" ng-show="accountingPeriods.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th translate>{{ 'invoices.start_date' }}</th>
|
||||
<th translate>{{ 'invoices.end_date' }}</th>
|
||||
<th translate>{{ 'invoices.closed_at' }}</th>
|
||||
<th translate>{{ 'invoices.closed_by' }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="period in accountingPeriods">
|
||||
<td>{{period.start_at | amDateFormat:'L'}}</td>
|
||||
<td>{{period.end_at | amDateFormat:'L'}}</td>
|
||||
<td>{{period.closed_at | amDateFormat:'L'}}</td>
|
||||
<td>{{period.user_name}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div ng-show="accountingPeriods.length === 0" translate>{{ 'invoices.no_periods'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-click="ok()" ng-disabled="closePeriodForm.$invalid" translate>{{ 'confirm' }}</button>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'cancel' }}</button>
|
||||
</div>
|
@ -7,10 +7,14 @@
|
||||
</div>
|
||||
<div class="col-xs-10 col-sm-10 col-md-8 b-l">
|
||||
<section class="heading-title">
|
||||
<h1 translate>{{ 'invoices' }}</h1>
|
||||
<h1 translate>{{ 'invoices.invoices' }}</h1>
|
||||
</section>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
|
||||
<section class="heading-actions wrapper">
|
||||
<a class="btn btn-lg btn-default rounded m-t-sm text-sm" ng-click="closeAnAccountingPeriod()"><i class="fa fa-calendar-check-o"></i></a>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -18,14 +22,14 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<uib-tabset justified="true">
|
||||
<uib-tab heading="{{ 'invoices_list' | translate }}">
|
||||
<h3 class="m-t-xs"><i class="fa fa-filter"></i> {{ 'filter_invoices' | translate }}</h3>
|
||||
<uib-tab heading="{{ 'invoices.invoices_list' | translate }}">
|
||||
<h3 class="m-t-xs"><i class="fa fa-filter"></i> {{ 'invoices.filter_invoices' | translate }}</h3>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" translate>{{ 'invoice_#_' }}</span>
|
||||
<span class="input-group-addon" translate>{{ 'invoices.invoice_#_' }}</span>
|
||||
<input type="text" ng-model="searchInvoice.reference" class="form-control" placeholder="" ng-change="handleFilterChange()">
|
||||
</div>
|
||||
</div>
|
||||
@ -34,7 +38,7 @@
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" translate>{{ 'customer_' }}</span>
|
||||
<span class="input-group-addon" translate>{{ 'invoices.customer_' }}</span>
|
||||
<input type="text" ng-model="searchInvoice.name" class="form-control" placeholder="" ng-change="handleFilterChange()">
|
||||
</div>
|
||||
</div>
|
||||
@ -43,7 +47,7 @@
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">{{ "date_" | translate }}</span>
|
||||
<span class="input-group-addon">{{ "invoices.date_" | translate }}</span>
|
||||
<input type="date" ng-model="searchInvoice.date" class="form-control" ng-change="handleFilterChange()">
|
||||
</div>
|
||||
</div>
|
||||
@ -57,13 +61,13 @@
|
||||
<table class="table" ng-if="invoices.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:15%"><a href="" ng-click="setOrderInvoice('reference')">{{ 'invoice_#' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': orderInvoice=='reference', 'fa fa-sort-numeric-desc': orderInvoice=='-reference', 'fa fa-arrows-v': orderInvoice }"></i></a></th>
|
||||
<th style="width:15%"><a href="" ng-click="setOrderInvoice('reference')">{{ 'invoices.invoice_#' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': orderInvoice=='reference', 'fa fa-sort-numeric-desc': orderInvoice=='-reference', 'fa fa-arrows-v': orderInvoice }"></i></a></th>
|
||||
|
||||
<th style="width:20%"><a href="" ng-click="setOrderInvoice('date')">{{ 'date' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': orderInvoice=='date', 'fa fa-sort-numeric-desc': orderInvoice=='-date', 'fa fa-arrows-v': orderInvoice }"></i></a></th>
|
||||
<th style="width:20%"><a href="" ng-click="setOrderInvoice('date')">{{ 'invoices.date' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': orderInvoice=='date', 'fa fa-sort-numeric-desc': orderInvoice=='-date', 'fa fa-arrows-v': orderInvoice }"></i></a></th>
|
||||
|
||||
<th style="width:10%"><a href="" ng-click="setOrderInvoice('total')"> {{ 'price' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': orderInvoice=='total', 'fa fa-sort-numeric-desc': orderInvoice=='-total', 'fa fa-arrows-v': orderInvoice }"></i></a></th>
|
||||
<th style="width:10%"><a href="" ng-click="setOrderInvoice('total')"> {{ 'invoices.price' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': orderInvoice=='total', 'fa fa-sort-numeric-desc': orderInvoice=='-total', 'fa fa-arrows-v': orderInvoice }"></i></a></th>
|
||||
|
||||
<th style="width:20%"><a href="" ng-click="setOrderInvoice('name')">{{ 'customer' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': orderInvoice=='name', 'fa fa-sort-alpha-desc': orderInvoice=='-name', 'fa fa-arrows-v': orderInvoice }"></i></a></th>
|
||||
<th style="width:20%"><a href="" ng-click="setOrderInvoice('name')">{{ 'invoices.customer' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': orderInvoice=='name', 'fa fa-sort-alpha-desc': orderInvoice=='-name', 'fa fa-arrows-v': orderInvoice }"></i></a></th>
|
||||
|
||||
<th style="width:30%"></th>
|
||||
</tr>
|
||||
@ -78,13 +82,13 @@
|
||||
<td>
|
||||
<div class="buttons">
|
||||
<a class="btn btn-default" ng-href="api/invoices/{{invoice.id}}/download" target="_blank" ng-if="!invoice.is_avoir">
|
||||
<i class="fa fa-file-pdf-o"></i> {{ 'download_the_invoice' | translate }}
|
||||
<i class="fa fa-file-pdf-o"></i> {{ 'invoices.download_the_invoice' | translate }}
|
||||
</a>
|
||||
<a class="btn btn-default" ng-href="api/invoices/{{invoice.id}}/download" target="_blank" ng-if="invoice.is_avoir">
|
||||
<i class="fa fa-file-pdf-o"></i> {{ 'download_the_credit_note' | translate }}
|
||||
<i class="fa fa-file-pdf-o"></i> {{ 'invoices.download_the_credit_note' | translate }}
|
||||
</a>
|
||||
<a class="btn btn-default" ng-click="generateAvoirForInvoice(invoice)" ng-if="(!invoice.has_avoir || invoice.has_avoir == 'partial') && !invoice.is_avoir && !invoice.prevent_refund">
|
||||
<i class="fa fa-reply"></i> {{ 'credit_note' | translate }}
|
||||
<a class="btn btn-default" ng-click="generateAvoirForInvoice(invoice)" ng-if="(!invoice.has_avoir || invoice.has_avoir == 'partial') && !invoice.is_avoir && !invoice.prevent_refund && !isDateClosed(invoice.created_at)">
|
||||
<i class="fa fa-reply"></i> {{ 'invoices.credit_note' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
@ -92,9 +96,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-warning" ng-click="showNextInvoices()" ng-hide="noMoreResults"><i class="fa fa-search-plus" aria-hidden="true"></i> {{ 'display_more_invoices' | translate }}</button>
|
||||
<button class="btn btn-warning" ng-click="showNextInvoices()" ng-hide="noMoreResults"><i class="fa fa-search-plus" aria-hidden="true"></i> {{ 'invoices.display_more_invoices' | translate }}</button>
|
||||
</div>
|
||||
<p ng-if="invoices.length == 0" translate>{{ 'no_invoices_for_now' }}</p>
|
||||
<p ng-if="invoices.length == 0" translate>{{ 'invoices.no_invoices_for_now' }}</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -103,7 +107,7 @@
|
||||
|
||||
|
||||
|
||||
<uib-tab heading="{{ 'invoicing_settings' | translate }}">
|
||||
<uib-tab heading="{{ 'invoices.invoicing_settings' | translate }}">
|
||||
<form class="invoice-placeholder">
|
||||
<div class="invoice-logo" style="background-image: url({{invoice.logo}});">
|
||||
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:/font:FontAwesome/icon" bs-holder ng-if="!invoice.logo" class="img-responsive">
|
||||
@ -111,79 +115,79 @@
|
||||
<div class="tools-box">
|
||||
<div class="btn-group">
|
||||
<div class="btn btn-default btn-file">
|
||||
<i class="fa fa-edit"></i> {{ 'change_logo' | translate }}
|
||||
<i class="fa fa-edit"></i> {{ 'invoices.change_logo' | translate }}
|
||||
<input type="file" accept="image/png,image/jpeg,image/x-png,image/pjpeg" name="invoice[logo][attachment]" ng-model="invoice.logo" base-sixty-four-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-buyer-infos">
|
||||
<strong translate>{{ 'john_smith' }}</strong>
|
||||
<div translate>{{ 'john_smith@example_com' }}</div>
|
||||
<strong translate>{{ 'invoices.john_smith' }}</strong>
|
||||
<div translate>{{ 'invoices.john_smith@example_com' }}</div>
|
||||
</div>
|
||||
<div class="invoice-reference invoice-editable" ng-click="openEditReference()">{{ 'invoice_reference_' | translate }} {{mkReference()}}</div>
|
||||
<div class="invoice-code invoice-editable" ng-show="invoice.code.active" ng-click="openEditCode()">{{ 'code_' | translate }} {{invoice.code.model}}</div>
|
||||
<div class="invoice-code invoice-activable" ng-show="!invoice.code.active" ng-click="openEditCode()" translate>{{ 'code_disabled' }}</div>
|
||||
<div class="invoice-order invoice-editable" ng-click="openEditInvoiceNb()"> {{ 'order_#' | translate }} {{mkNumber()}}</div>
|
||||
<div class="invoice-date">{{ 'invoice_issued_on_DATE_at_TIME' | translate:{DATE:(today | amDateFormat:'L'), TIME:(today | amDateFormat:'LT')} }}</div>
|
||||
<div class="invoice-reference invoice-editable" ng-click="openEditReference()">{{ 'invoices.invoice_reference_' | translate }} {{mkReference()}}</div>
|
||||
<div class="invoice-code invoice-editable" ng-show="invoice.code.active" ng-click="openEditCode()">{{ 'invoices.code_' | translate }} {{invoice.code.model}}</div>
|
||||
<div class="invoice-code invoice-activable" ng-show="!invoice.code.active" ng-click="openEditCode()" translate>{{ 'invoices.code_disabled' }}</div>
|
||||
<div class="invoice-order invoice-editable" ng-click="openEditInvoiceNb()"> {{ 'invoices.order_#' | translate }} {{mkNumber()}}</div>
|
||||
<div class="invoice-date">{{ 'invoices.invoice_issued_on_DATE_at_TIME' | translate:{DATE:(today | amDateFormat:'L'), TIME:(today | amDateFormat:'LT')} }}</div>
|
||||
<div class="invoice-object">
|
||||
{{ 'object_reservation_of_john_smith_on_DATE_at_TIME' | translate:{DATE:(inOneWeek | amDateFormat:'L'), TIME:(inOneWeek | amDateFormat:'LT')} }}
|
||||
{{ 'invoices.object_reservation_of_john_smith_on_DATE_at_TIME' | translate:{DATE:(inOneWeek | amDateFormat:'L'), TIME:(inOneWeek | amDateFormat:'LT')} }}
|
||||
</div>
|
||||
<div class="invoice-data">
|
||||
{{ 'order_summary' | translate }}
|
||||
{{ 'invoices.order_summary' | translate }}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th translate>{{ 'details' }}</th>
|
||||
<th class="right" translate>{{ 'amount' }}</th>
|
||||
<th translate>{{ 'invoices.details' }}</th>
|
||||
<th class="right" translate>{{ 'invoices.amount' }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ 'machine_booking-3D_printer' | translate }} {{inOneWeek | amDateFormat:'LLL'}} - {{inOneWeekAndOneHour | amDateFormat:'LT'}}</td>
|
||||
<td>{{ 'invoices.machine_booking-3D_printer' | translate }} {{inOneWeek | amDateFormat:'LLL'}} - {{inOneWeekAndOneHour | amDateFormat:'LT'}}</td>
|
||||
<td class="right">{{30.0 | currency}}</td>
|
||||
</tr>
|
||||
|
||||
<tr class="invoice-total" ng-class="{'bold vat-line':invoice.VAT.active}">
|
||||
<td ng-show="!invoice.VAT.active" translate>{{ 'total_amount' }}</td>
|
||||
<td ng-show="invoice.VAT.active" translate>{{ 'total_including_all_taxes' }}</td>
|
||||
<td ng-show="!invoice.VAT.active" translate>{{ 'invoices.total_amount' }}</td>
|
||||
<td ng-show="invoice.VAT.active" translate>{{ 'invoices.total_including_all_taxes' }}</td>
|
||||
<td class="right">{{30.0 | currency}}</td>
|
||||
</tr>
|
||||
|
||||
<tr class="invoice-vat invoice-activable" ng-click="openEditVAT()" ng-show="!invoice.VAT.active">
|
||||
<td translate>{{ 'VAT_disabled' }}</td>
|
||||
<td translate>{{ 'invoices.VAT_disabled' }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr class="invoice-vat invoice-editable vat-line italic" ng-click="openEditVAT()" ng-show="invoice.VAT.active">
|
||||
<td>{{ 'including_VAT' | translate }} {{invoice.VAT.rate}} %</td>
|
||||
<td>{{ 'invoices.including_VAT' | translate }} {{invoice.VAT.rate}} %</td>
|
||||
<td>{{30-(30/(invoice.VAT.rate/100+1)) | currency}}</td>
|
||||
</tr>
|
||||
<tr class="invoice-ht vat-line italic" ng-show="invoice.VAT.active">
|
||||
<td translate>{{ 'including_total_excluding_taxes' }}</td>
|
||||
<td translate>{{ 'invoices.including_total_excluding_taxes' }}</td>
|
||||
<td>{{30/(invoice.VAT.rate/100+1) | currency}}</td>
|
||||
</tr>
|
||||
<tr class="invoice-payed vat-line bold" ng-show="invoice.VAT.active">
|
||||
<td translate>{{ 'including_amount_payed_on_ordering' }}</td>
|
||||
<td translate>{{ 'invoices.including_amount_payed_on_ordering' }}</td>
|
||||
<td>{{30.0 | currency}}</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="invoice-payment" translate translate-values="{DATE:(today | amDateFormat:'L'), TIME:(today | amDateFormat:'LT'), AMOUNT:(30.0 | currency)}">
|
||||
{{ 'settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT' }}
|
||||
{{ 'invoices.settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT' }}
|
||||
</p>
|
||||
</div>
|
||||
<div medium-editor class="invoice-text invoice-editable" ng-model="invoice.text.content"
|
||||
options='{
|
||||
"placeholder": "{{ "important_notes" | translate }}",
|
||||
"placeholder": "{{ "invoices.important_notes" | translate }}",
|
||||
"buttons": ["underline"]
|
||||
}'
|
||||
ng-blur="textEditEnd($event)">
|
||||
</div>
|
||||
<div medium-editor class="invoice-legals invoice-editable" ng-model="invoice.legals.content"
|
||||
options='{
|
||||
"placeholder": "{{ "address_and_legal_information" | translate }}",
|
||||
"placeholder": "{{ "invoices.address_and_legal_information" | translate }}",
|
||||
"buttons": ["bold", "underline"]
|
||||
}'
|
||||
ng-blur="legalsEditEnd($event)">
|
||||
@ -199,28 +203,28 @@
|
||||
<script type="text/ng-template" id="editReference.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'invoice_reference' }}</h3>
|
||||
<h3 class="modal-title" translate>{{ 'invoices.invoice_reference' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body row">
|
||||
<div class="elements col-md-4">
|
||||
<h4>Éléments</h4>
|
||||
<ul>
|
||||
<li ng-click="invoice.reference.help = 'addYear.html'">{{ 'year' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addMonth.html'">{{ 'month' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addDay.html'">{{ 'day' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addInvoiceNumber.html'">{{ '#_of_invoice' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addOnlineInfo.html'">{{ 'online_sales' | translate }}</li>
|
||||
<%# <li ng-click="invoice.reference.help = 'addWalletInfo.html'">{{ 'wallet' | translate }}</li> %>
|
||||
<li ng-click="invoice.reference.help = 'addRefundInfo.html'">{{ 'refund' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addYear.html'">{{ 'invoices.year' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addMonth.html'">{{ 'invoices.month' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addDay.html'">{{ 'invoices.day' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addInvoiceNumber.html'">{{ 'invoices.#_of_invoice' | translate }}</li>
|
||||
<li ng-click="invoice.reference.help = 'addOnlineInfo.html'">{{ 'invoices.online_sales' | translate }}</li>
|
||||
<%# <li ng-click="invoice.reference.help = 'addWalletInfo.html'">{{ 'invoices.wallet' | translate }}</li> %>
|
||||
<li ng-click="invoice.reference.help = 'addRefundInfo.html'">{{ 'invoices.refund' | translate }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="model">
|
||||
<h4 translate>{{ 'model' }}</h4>
|
||||
<h4 translate>{{ 'invoices.model' }}</h4>
|
||||
<input type="text" class="form-control" ng-model="model">
|
||||
</div>
|
||||
<div class="help">
|
||||
<h4 translate>{{ 'documentation' }}</h4>
|
||||
<h4 translate>{{ 'invoices.documentation' }}</h4>
|
||||
<ng-include src="invoice.reference.help" autoscroll="true">
|
||||
</ng-include>
|
||||
</div>
|
||||
@ -235,83 +239,83 @@
|
||||
|
||||
<script type="text/ng-template" id="addYear.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>YY</strong></td><td translate>{{ '2_digits_year_(eg_70)' }}</td></tr>
|
||||
<tr><td><strong>YYYY</strong></td><td translate>{{ '4_digits_year_(eg_1970)' }}</td></tr>
|
||||
<tr><td><strong>YY</strong></td><td translate>{{ 'invoices.2_digits_year_(eg_70)' }}</td></tr>
|
||||
<tr><td><strong>YYYY</strong></td><td translate>{{ 'invoices.4_digits_year_(eg_1970)' }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addMonth.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>M</strong></td><td translate>{{ 'month_number_(eg_1)' }}</td></tr>
|
||||
<tr><td><strong>MM</strong></td><td translate>{{ '2_digits_month_number_(eg_01)' }}</td></tr>
|
||||
<tr><td><strong>MMM</strong></td><td translate>{{ '3_characters_month_name_(eg_JAN)' }}</td></tr>
|
||||
<tr><td><strong>M</strong></td><td translate>{{ 'invoices.month_number_(eg_1)' }}</td></tr>
|
||||
<tr><td><strong>MM</strong></td><td translate>{{ 'invoices.2_digits_month_number_(eg_01)' }}</td></tr>
|
||||
<tr><td><strong>MMM</strong></td><td translate>{{ 'invoices.3_characters_month_name_(eg_JAN)' }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addDay.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>D</strong></td><td translate>{{ 'day_in_the_month_(eg_1)' }}</td></tr>
|
||||
<tr><td><strong>DD</strong></td><td translate>{{ '2_digits_day_in_the_month_(eg_01)' }}</td></tr>
|
||||
<tr><td><strong>D</strong></td><td translate>{{ 'invoices.day_in_the_month_(eg_1)' }}</td></tr>
|
||||
<tr><td><strong>DD</strong></td><td translate>{{ 'invoices.2_digits_day_in_the_month_(eg_01)' }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addInvoiceNumber.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>dd...dd</strong></td><td translate>{{ '(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day)' }}</td></tr>
|
||||
<tr><td><strong>mm...mm</strong></td><td translate>{{ '(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month)' }}</td></tr>
|
||||
<tr><td><strong>yy...yy</strong></td><td translate>{{ '(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year)' }}</td></tr>
|
||||
<tr><td><strong>dd...dd</strong></td><td translate>{{ 'invoices.(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day)' }}</td></tr>
|
||||
<tr><td><strong>mm...mm</strong></td><td translate>{{ 'invoices.(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month)' }}</td></tr>
|
||||
<tr><td><strong>yy...yy</strong></td><td translate>{{ 'invoices.(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year)' }}</td></tr>
|
||||
</table>
|
||||
<span class="bottom-notes" translate>{{ 'beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left' }}</span>
|
||||
<span class="bottom-notes" translate>{{ 'invoices.beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left' }}</span>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addOrderNumber.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>nn...nn</strong></td><td translate>{{ '(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order)' }}</td></tr>
|
||||
<tr><td><strong>dd...dd</strong></td><td translate>{{ '(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day)' }}</td></tr>
|
||||
<tr><td><strong>mm...mm</strong></td><td translate>{{ '(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month)' }}</td></tr>
|
||||
<tr><td><strong>yy...yy</strong></td><td translate>{{ '(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year)' }}</td></tr>
|
||||
<tr><td><strong>nn...nn</strong></td><td translate>{{ 'invoices.(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order)' }}</td></tr>
|
||||
<tr><td><strong>dd...dd</strong></td><td translate>{{ 'invoices.(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day)' }}</td></tr>
|
||||
<tr><td><strong>mm...mm</strong></td><td translate>{{ 'invoices.(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month)' }}</td></tr>
|
||||
<tr><td><strong>yy...yy</strong></td><td translate>{{ 'invoices.(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year)' }}</td></tr>
|
||||
</table>
|
||||
<span class="bottom-notes" translate>{{ 'beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left' }}</span>
|
||||
<span class="bottom-notes" translate>{{ 'invoices.beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left' }}</span>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addOnlineInfo.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>X[texte]</strong></td><td>{{ 'add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ '(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe)' | translate }}</td></tr>
|
||||
<tr><td><strong>X[texte]</strong></td><td>{{ 'invoices.add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'invoices.this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ 'invoices.(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe)' | translate }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addWalletInfo.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>W[texte]</strong></td><td>{{ 'add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ '(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet)' | translate }}</td></tr>
|
||||
<tr><td><strong>W[texte]</strong></td><td>{{ 'invoices.add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'invoices.this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ 'invoices.(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet)' | translate }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addRefundInfo.html">
|
||||
<table class="invoice-element-legend">
|
||||
<tr><td><strong>R[texte]</strong></td><td>{{ 'add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned' | translate }}<mark translate>{{ 'this_will_never_be_added_when_an_online_sales_notice_is_present' }}</mark> {{ '(eg_R[/A]_will_add_/A_to_the_refund_invoices)' | translate }}</td></tr>
|
||||
<tr><td><strong>R[texte]</strong></td><td>{{ 'invoices.add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned' | translate }}<mark translate>{{ 'invoices.this_will_never_be_added_when_an_online_sales_notice_is_present' }}</mark> {{ 'invoices.(eg_R[/A]_will_add_/A_to_the_refund_invoices)' | translate }}</td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="editCode.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'code' }}</h3>
|
||||
<h3 class="modal-title" translate>{{ 'invoices.code' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="enableCode" class="control-label" translate>{{ 'enable_the_code' }}</label>
|
||||
<label for="enableCode" class="control-label" translate>{{ 'invoices.enable_the_code' }}</label>
|
||||
<input bs-switch
|
||||
ng-model="isSelected"
|
||||
id="enableCode"
|
||||
type="checkbox"
|
||||
class="form-control m-l-sm"
|
||||
switch-on-text="{{ 'enabled' | translate }}"
|
||||
switch-off-text="{{ 'disabled' | translate }}"
|
||||
switch-on-text="{{ 'invoices.enabled' | translate }}"
|
||||
switch-off-text="{{ 'invoices.disabled' | translate }}"
|
||||
switch-animate="true"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-show="isSelected">
|
||||
<label for="codeModel" class="control-label" translate>{{ 'code' }}</label>
|
||||
<label for="codeModel" class="control-label" translate>{{ 'invoices.code' }}</label>
|
||||
<input id="codeModel" type="text" ng-model="codeModel" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
@ -327,25 +331,25 @@
|
||||
<script type="text/ng-template" id="editNumber.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'order_number' }}</h3>
|
||||
<h3 class="modal-title" translate>{{ 'invoices.order_number' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body row">
|
||||
<div class="elements col-md-4">
|
||||
<h4 translate>{{ 'elements' }}</h4>
|
||||
<h4 translate>{{ 'invoices.elements' }}</h4>
|
||||
<ul>
|
||||
<li ng-click="invoice.number.help = 'addYear.html'">{{ 'year' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addMonth.html'">{{ 'month' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addDay.html'">{{ 'day' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addOrderNumber.html'">{{ 'order_#' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addYear.html'">{{ 'invoices.year' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addMonth.html'">{{ 'invoices.month' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addDay.html'">{{ 'invoices.day' | translate }}</li>
|
||||
<li ng-click="invoice.number.help = 'addOrderNumber.html'">{{ 'invoices.order_#' | translate }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="model">
|
||||
<h4 translate>{{ 'model' }}</h4>
|
||||
<h4 translate>{{ 'invoices.model' }}</h4>
|
||||
<input type="text" class="form-control" ng-model="model">
|
||||
</div>
|
||||
<div class="help">
|
||||
<h4 translate>{{ 'documentation' }}</h4>
|
||||
<h4 translate>{{ 'invoices.documentation' }}</h4>
|
||||
<ng-include src="invoice.number.help" autoscroll="true">
|
||||
</ng-include>
|
||||
</div>
|
||||
@ -362,23 +366,23 @@
|
||||
<script type="text/ng-template" id="editVAT.html">
|
||||
<div class="custom-invoice">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'VAT' }}</h3>
|
||||
<h3 class="modal-title" translate>{{ 'invoices.VAT' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="enableVAT" class="control-label" translate>{{ 'enable_VAT' }}</label>
|
||||
<label for="enableVAT" class="control-label" translate>{{ 'invoices.enable_VAT' }}</label>
|
||||
<input bs-switch
|
||||
ng-model="isSelected"
|
||||
id="enableVAT"
|
||||
type="checkbox"
|
||||
class="form-control m-l-sm"
|
||||
switch-on-text="{{ 'enabled' | translate }}"
|
||||
switch-off-text="{{ 'disabled' | translate }}"
|
||||
switch-on-text="{{ 'invoices.enabled' | translate }}"
|
||||
switch-off-text="{{ 'invoices.disabled' | translate }}"
|
||||
switch-animate="true"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-show="isSelected">
|
||||
<label for="vatRate" class="control-label" translate>{{ 'VAT_rate' }}</label>
|
||||
<label for="vatRate" class="control-label" translate>{{ 'invoices.VAT_rate' }}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">% </span>
|
||||
<input id="vatRate" type="number" ng-model="rate" class="form-control" min="0" max="100"/>
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Abuse.
|
||||
# Typical action is an user reporting an abuse on a project
|
||||
class API::AbusesController < API::ApiController
|
||||
before_action :authenticate_user!, except: :create
|
||||
|
||||
|
45
app/controllers/api/accounting_periods_controller.rb
Normal file
45
app/controllers/api/accounting_periods_controller.rb
Normal file
@ -0,0 +1,45 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of AccountingPeriod
|
||||
class API::AccountingPeriodsController < API::ApiController
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :set_period, only: %i[show]
|
||||
|
||||
def index
|
||||
@accounting_periods = AccountingPeriodService.all_periods_with_users
|
||||
end
|
||||
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize AccountingPeriod
|
||||
@accounting_period = AccountingPeriod.new(period_params.merge(closed_at: DateTime.now, closed_by: current_user.id))
|
||||
if @accounting_period.save
|
||||
render :show, status: :created, location: @accounting_period
|
||||
else
|
||||
render json: @accounting_period.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def last_closing_end
|
||||
authorize AccountingPeriod
|
||||
last_period = AccountingPeriodService.find_last_period
|
||||
if last_period.nil?
|
||||
invoice = Invoice.order(:created_at).first
|
||||
@last_end = invoice.created_at if invoice
|
||||
else
|
||||
@last_end = last_period.end_at + 1.day
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_period
|
||||
@tag = AccountingPeriod.find(params[:id])
|
||||
end
|
||||
|
||||
def period_params
|
||||
params.require(:accounting_period).permit(:start_at, :end_at)
|
||||
end
|
||||
end
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type User with role 'admin'.
|
||||
class API::AdminsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type AgeRange
|
||||
# AgeRange are used in Events
|
||||
class API::AgeRangesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index]
|
||||
before_action :set_age_range, only: [:show, :update, :destroy]
|
||||
before_action :set_age_range, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@age_ranges = AgeRange.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize AgeRange
|
||||
|
@ -1,15 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of Invoice and Avoir
|
||||
class API::InvoicesController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_invoice, only: [:show, :download]
|
||||
before_action :set_invoice, only: %i[show download]
|
||||
|
||||
def index
|
||||
authorize Invoice
|
||||
@invoices = Invoice.includes(:avoir, :invoiced, invoice_items: [:subscription, :invoice_item], user: [:profile, :trainings]).all.order('reference DESC')
|
||||
@invoices = Invoice.includes(
|
||||
:avoir, :invoiced, invoice_items: %i[subscription invoice_item], user: %i[profile trainings]
|
||||
).all.order('reference DESC')
|
||||
end
|
||||
|
||||
def download
|
||||
authorize @invoice
|
||||
send_file File.join(Rails.root, @invoice.file), :type => 'application/pdf', :disposition => 'attachment'
|
||||
send_file File.join(Rails.root, @invoice.file), type: 'application/pdf', disposition: 'attachment'
|
||||
end
|
||||
|
||||
def list
|
||||
@ -17,44 +22,18 @@ class API::InvoicesController < API::ApiController
|
||||
|
||||
p = params.require(:query).permit(:number, :customer, :date, :order_by, :page, :size)
|
||||
|
||||
unless p[:page].is_a? Integer
|
||||
render json: {error: 'page must be an integer'}, status: :unprocessable_entity
|
||||
end
|
||||
render json: { error: 'page must be an integer' }, status: :unprocessable_entity and return unless p[:page].is_a? Integer
|
||||
|
||||
unless p[:size].is_a? Integer
|
||||
render json: {error: 'size must be an integer'}, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
|
||||
direction = (p[:order_by][0] == '-' ? 'DESC' : 'ASC')
|
||||
order_key = (p[:order_by][0] == '-' ? p[:order_by][1, p[:order_by].size] : p[:order_by])
|
||||
|
||||
case order_key
|
||||
when 'reference'
|
||||
order_key = 'invoices.reference'
|
||||
when 'date'
|
||||
order_key = 'invoices.created_at'
|
||||
when 'total'
|
||||
order_key = 'invoices.total'
|
||||
when 'name'
|
||||
order_key = 'profiles.first_name'
|
||||
else
|
||||
order_key = 'invoices.id'
|
||||
end
|
||||
|
||||
@invoices = Invoice.includes(:avoir, :invoiced, invoice_items: [:subscription, :invoice_item], user: [:profile, :trainings])
|
||||
.joins(:user => :profile)
|
||||
.order("#{order_key} #{direction}")
|
||||
.page(p[:page])
|
||||
.per(p[:size])
|
||||
|
||||
# ILIKE => PostgreSQL case-insensitive LIKE
|
||||
@invoices = @invoices.where('invoices.reference LIKE :search', search: "#{p[:number].to_s}%") if p[:number].size > 0
|
||||
@invoices = @invoices.where('profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search', search: "%#{p[:customer]}%") if p[:customer].size > 0
|
||||
@invoices = @invoices.where("date_trunc('day', invoices.created_at) = :search", search: "%#{DateTime.iso8601(p[:date]).to_time.to_date.to_s}%") unless p[:date].nil?
|
||||
|
||||
@invoices
|
||||
render json: { error: 'size must be an integer' }, status: :unprocessable_entity and return unless p[:size].is_a? Integer
|
||||
|
||||
order = InvoicesService.parse_order(p[:order_by])
|
||||
@invoices = InvoicesService.list(
|
||||
order[:order_key],
|
||||
order[:direction],
|
||||
p[:page],
|
||||
p[:size],
|
||||
number: p[:number], customer: p[:customer], date: p[:date]
|
||||
)
|
||||
end
|
||||
|
||||
# only for create refund invoices (avoir)
|
||||
@ -64,9 +43,7 @@ class API::InvoicesController < API::ApiController
|
||||
@avoir = invoice.build_avoir(avoir_params)
|
||||
if @avoir.save
|
||||
# when saved, expire the subscription if needed
|
||||
if @avoir.subscription_to_expire
|
||||
@avoir.expire_subscription
|
||||
end
|
||||
@avoir.expire_subscription if @avoir.subscription_to_expire
|
||||
# then answer the API call
|
||||
render :avoir, status: :created
|
||||
else
|
||||
@ -75,11 +52,13 @@ class API::InvoicesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def avoir_params
|
||||
params.require(:avoir).permit(:invoice_id, :avoir_date, :avoir_mode, :subscription_to_expire, :description, :invoice_items_ids => [])
|
||||
end
|
||||
|
||||
def set_invoice
|
||||
@invoice = Invoice.find(params[:id])
|
||||
end
|
||||
def avoir_params
|
||||
params.require(:avoir).permit(:invoice_id, :avoir_date, :avoir_mode, :subscription_to_expire, :description,
|
||||
invoice_items_ids: [])
|
||||
end
|
||||
|
||||
def set_invoice
|
||||
@invoice = Invoice.find(params[:id])
|
||||
end
|
||||
end
|
||||
|
@ -1,15 +1,13 @@
|
||||
|
||||
class API::TagsController < API::ApiController
|
||||
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_tag, only: [:show, :update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_tag, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@tags = Tag.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Tag
|
||||
@ -44,4 +42,4 @@ class API::TagsController < API::ApiController
|
||||
def tag_params
|
||||
params.require(:tag).permit(:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,12 @@
|
||||
class API::ThemesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_theme, only: [:show, :update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_theme, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@themes = Theme.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Theme
|
||||
@ -35,11 +34,12 @@ class API::ThemesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_theme
|
||||
@theme = Theme.find(params[:id])
|
||||
end
|
||||
|
||||
def theme_params
|
||||
params.require(:theme).permit(:name)
|
||||
end
|
||||
def set_theme
|
||||
@theme = Theme.find(params[:id])
|
||||
end
|
||||
|
||||
def theme_params
|
||||
params.require(:theme).permit(:name)
|
||||
end
|
||||
end
|
||||
|
@ -1,8 +1,8 @@
|
||||
class API::TrainingsController < API::ApiController
|
||||
include ApplicationHelper
|
||||
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_training, only: [:update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_training, only: %i[update destroy]
|
||||
|
||||
def index
|
||||
@requested_attributes = params[:requested_attributes]
|
||||
@ -12,7 +12,8 @@ class API::TrainingsController < API::ApiController
|
||||
end
|
||||
|
||||
if attribute_requested?(@requested_attributes, 'availabilities')
|
||||
@trainings = @trainings.includes(:availabilities => [:slots => [:reservation => [:user => [:profile, :trainings]]]]).order('availabilities.start_at DESC')
|
||||
@trainings = @trainings.includes(availabilities: [slots: [reservation: [user: %i[profile trainings]]]])
|
||||
.order('availabilities.start_at DESC')
|
||||
end
|
||||
end
|
||||
|
||||
@ -39,12 +40,10 @@ class API::TrainingsController < API::ApiController
|
||||
end
|
||||
|
||||
head :no_content
|
||||
elsif @training.update(training_params)
|
||||
render :show, status: :ok, location: @training
|
||||
else
|
||||
if @training.update(training_params)
|
||||
render :show, status: :ok, location: @training
|
||||
else
|
||||
render json: @training.errors, status: :unprocessable_entity
|
||||
end
|
||||
render json: @training.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@ -57,19 +56,24 @@ class API::TrainingsController < API::ApiController
|
||||
def availabilities
|
||||
authorize Training
|
||||
@training = Training.find(params[:id])
|
||||
@availabilities = @training.availabilities.includes(slots: {reservations: {user: [:profile, :trainings] }}).order('start_at DESC')
|
||||
@availabilities = @training.availabilities
|
||||
.includes(slots: { reservations: { user: %i[profile trainings] } })
|
||||
.order('start_at DESC')
|
||||
end
|
||||
|
||||
private
|
||||
def set_training
|
||||
@training = Training.find(params[:id])
|
||||
end
|
||||
|
||||
def valid_training_params
|
||||
params.require(:training).permit(:id, users: [])
|
||||
end
|
||||
def set_training
|
||||
@training = Training.find(params[:id])
|
||||
end
|
||||
|
||||
def training_params
|
||||
params.require(:training).permit(:id, :name, :description, :machine_ids, :plan_ids, :nb_total_places, :public_page, :disabled, training_image_attributes: [:attachment], machine_ids: [], plan_ids: [])
|
||||
end
|
||||
def valid_training_params
|
||||
params.require(:training).permit(:id, users: [])
|
||||
end
|
||||
|
||||
def training_params
|
||||
params.require(:training)
|
||||
.permit(:id, :name, :description, :machine_ids, :plan_ids, :nb_total_places, :public_page, :disabled,
|
||||
training_image_attributes: [:attachment], machine_ids: [], plan_ids: [])
|
||||
end
|
||||
end
|
||||
|
@ -4,8 +4,8 @@ class API::TranslationsController < API::ApiController
|
||||
|
||||
def show
|
||||
@translations = I18n.t params[:state]
|
||||
if @translations.class.name == String.name and @translations.start_with?('translation missing')
|
||||
render json: {error: @translations}, status: :unprocessable_entity
|
||||
if @translations.class.name == String.name && @translations.start_with?('translation missing')
|
||||
render json: { error: @translations }, status: :unprocessable_entity
|
||||
else
|
||||
render json: @translations, status: :ok
|
||||
end
|
||||
@ -15,4 +15,4 @@ class API::TranslationsController < API::ApiController
|
||||
I18n.locale = params[:locale] || I18n.default_locale
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ class API::UsersController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
def index
|
||||
if current_user.is_admin? and params[:role] == 'partner'
|
||||
if current_user.is_admin? && params[:role] == 'partner'
|
||||
@users = User.with_role(:partner).includes(:profile)
|
||||
else
|
||||
head 403
|
||||
@ -12,9 +12,16 @@ class API::UsersController < API::ApiController
|
||||
def create
|
||||
if current_user.is_admin?
|
||||
generated_password = Devise.friendly_token.first(8)
|
||||
@user = User.new(email: partner_params[:email], username: "#{partner_params[:first_name]}#{partner_params[:last_name]}",
|
||||
password: generated_password, password_confirmation: generated_password, group_id: Group.first.id)
|
||||
@user.build_profile(first_name: partner_params[:first_name], last_name: partner_params[:last_name], gender: true, birthday: Time.now, phone: '0000000000')
|
||||
@user = User.new(email: partner_params[:email],
|
||||
username: "#{partner_params[:first_name]}#{partner_params[:last_name]}",
|
||||
password: generated_password,
|
||||
password_confirmation: generated_password,
|
||||
group_id: Group.first.id)
|
||||
@user.build_profile(first_name: partner_params[:first_name],
|
||||
last_name: partner_params[:last_name],
|
||||
gender: true,
|
||||
birthday: Time.now,
|
||||
phone: '0000000000')
|
||||
|
||||
if @user.save
|
||||
@user.remove_role :member
|
||||
@ -29,6 +36,7 @@ class API::UsersController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def partner_params
|
||||
params.require(:user).permit(:email, :first_name, :last_name)
|
||||
end
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
class API::VersionController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
|
@ -29,6 +29,7 @@ class API::WalletController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def credit_params
|
||||
params.permit(:id, :amount, :avoir, :avoir_date, :avoir_description)
|
||||
end
|
||||
|
42
app/models/accounting_period.rb
Normal file
42
app/models/accounting_period.rb
Normal file
@ -0,0 +1,42 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# AccountingPeriod is a period of N days (N > 0) which as been closed by an admin
|
||||
# to prevent writing new accounting lines (invoices & refunds) during this period of time.
|
||||
class AccountingPeriod < ActiveRecord::Base
|
||||
before_destroy { false }
|
||||
before_update { false }
|
||||
after_create :archive_closed_data
|
||||
|
||||
validates :start_at, :end_at, :closed_at, :closed_by, presence: true
|
||||
validates_with DateRangeValidator
|
||||
validates_with PeriodOverlapValidator
|
||||
|
||||
def delete
|
||||
false
|
||||
end
|
||||
|
||||
def archive_file
|
||||
dir = 'accounting'
|
||||
|
||||
# create directory if it doesn't exists (accounting)
|
||||
FileUtils.mkdir_p dir
|
||||
"#{dir}/#{start_at.iso8601}_#{end_at.iso8601}.json"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def to_json_archive(invoices)
|
||||
ApplicationController.new.view_context.render(
|
||||
partial: 'archive/accounting',
|
||||
locals: { invoices: invoices },
|
||||
formats: [:json],
|
||||
handlers: [:jbuilder]
|
||||
)
|
||||
end
|
||||
|
||||
def archive_closed_data
|
||||
data = Invoice.where('created_at >= :start_date AND created_at < :end_date', start_date: start_at, end_date: end_at)
|
||||
.includes(:invoice_items)
|
||||
File.write(archive_file, to_json_archive(data))
|
||||
end
|
||||
end
|
@ -1,7 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Avoir is a special type of Invoice, which it inherits. It is used to
|
||||
# refund an user, based on a previous invoice, or to credit an user's wallet.
|
||||
class Avoir < Invoice
|
||||
belongs_to :invoice
|
||||
|
||||
validates :avoir_mode, inclusion: {in: %w[stripe cheque transfer none cash wallet] }
|
||||
validates :avoir_mode, inclusion: { in: %w[stripe cheque transfer none cash wallet] }
|
||||
|
||||
attr_accessor :invoice_items_ids
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
# Invoice correspond to a single purchase made by an user. This purchase may
|
||||
# include reservation(s) and/or a subscription
|
||||
class Invoice < ActiveRecord::Base
|
||||
include NotifyWith::NotificationAttachedObject
|
||||
require 'fileutils'
|
||||
@ -13,21 +15,22 @@ class Invoice < ActiveRecord::Base
|
||||
has_one :avoir, class_name: 'Invoice', foreign_key: :invoice_id, dependent: :destroy
|
||||
|
||||
after_create :update_reference
|
||||
after_commit :generate_and_send_invoice, on: [:create], :if => :persisted?
|
||||
after_commit :generate_and_send_invoice, on: [:create], if: :persisted?
|
||||
|
||||
validates_with ClosedPeriodValidator
|
||||
|
||||
def file
|
||||
dir = "invoices/#{user.id}"
|
||||
|
||||
# create directories if they doesn't exists (invoice & user_id)
|
||||
FileUtils::mkdir_p dir
|
||||
"#{dir}/#{self.filename}"
|
||||
FileUtils.mkdir_p dir
|
||||
"#{dir}/#{filename}"
|
||||
end
|
||||
|
||||
def filename
|
||||
"#{ENV['INVOICE_PREFIX']}-#{self.id}_#{self.created_at.strftime('%d%m%Y')}.pdf"
|
||||
"#{ENV['INVOICE_PREFIX']}-#{id}_#{created_at.strftime('%d%m%Y')}.pdf"
|
||||
end
|
||||
|
||||
|
||||
def generate_reference
|
||||
pattern = Setting.find_by(name: 'invoice_reference').value
|
||||
|
||||
@ -62,14 +65,14 @@ class Invoice < ActiveRecord::Base
|
||||
reference.gsub!(/DD(?![^\[]*\])/, Time.now.strftime('%-d'))
|
||||
|
||||
# information about online selling (X[text])
|
||||
if self.stp_invoice_id
|
||||
if stp_invoice_id
|
||||
reference.gsub!(/X\[([^\]]+)\]/, '\1')
|
||||
else
|
||||
reference.gsub!(/X\[([^\]]+)\]/, ''.to_s)
|
||||
end
|
||||
|
||||
# information about wallet (W[text])
|
||||
#reference.gsub!(/W\[([^\]]+)\]/, ''.to_s)
|
||||
# reference.gsub!(/W\[([^\]]+)\]/, ''.to_s)
|
||||
|
||||
# remove information about refunds (R[text])
|
||||
reference.gsub!(/R\[([^\]]+)\]/, ''.to_s)
|
||||
@ -83,7 +86,7 @@ class Invoice < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def order_number
|
||||
pattern = Setting.find_by({name: 'invoice_order-nb'}).value
|
||||
pattern = Setting.find_by(name: 'invoice_order-nb').value
|
||||
|
||||
# global invoice number (nn..nn)
|
||||
reference = pattern.gsub(/n+(?![^\[]*\])/) do |match|
|
||||
@ -103,34 +106,35 @@ class Invoice < ActiveRecord::Base
|
||||
end
|
||||
|
||||
# full year (YYYY)
|
||||
reference.gsub!(/YYYY(?![^\[]*\])/, self.created_at.strftime('%Y'))
|
||||
reference.gsub!(/YYYY(?![^\[]*\])/, created_at.strftime('%Y'))
|
||||
# year without century (YY)
|
||||
reference.gsub!(/YY(?![^\[]*\])/, self.created_at.strftime('%y'))
|
||||
reference.gsub!(/YY(?![^\[]*\])/, created_at.strftime('%y'))
|
||||
|
||||
# abreviated month name (MMM)
|
||||
reference.gsub!(/MMM(?![^\[]*\])/, self.created_at.strftime('%^b'))
|
||||
# abbreviated month name (MMM)
|
||||
reference.gsub!(/MMM(?![^\[]*\])/, created_at.strftime('%^b'))
|
||||
# month of the year, zero-padded (MM)
|
||||
reference.gsub!(/MM(?![^\[]*\])/, self.created_at.strftime('%m'))
|
||||
reference.gsub!(/MM(?![^\[]*\])/, created_at.strftime('%m'))
|
||||
# month of the year, non zero-padded (M)
|
||||
reference.gsub!(/M(?![^\[]*\])/, self.created_at.strftime('%-m'))
|
||||
reference.gsub!(/M(?![^\[]*\])/, created_at.strftime('%-m'))
|
||||
|
||||
# day of the month, zero-padded (DD)
|
||||
reference.gsub!(/DD(?![^\[]*\])/, self.created_at.strftime('%d'))
|
||||
reference.gsub!(/DD(?![^\[]*\])/, created_at.strftime('%d'))
|
||||
# day of the month, non zero-padded (DD)
|
||||
reference.gsub!(/DD(?![^\[]*\])/, self.created_at.strftime('%-d'))
|
||||
reference.gsub!(/DD(?![^\[]*\])/, created_at.strftime('%-d'))
|
||||
|
||||
reference
|
||||
end
|
||||
|
||||
# for debug & used by rake task "fablab:regenerate_invoices"
|
||||
def regenerate_invoice_pdf
|
||||
pdf = ::PDF::Invoice.new(self).render
|
||||
pdf = ::PDF::Invoice.new(self, nil).render
|
||||
File.binwrite(file, pdf)
|
||||
end
|
||||
|
||||
def build_avoir(attrs = {})
|
||||
raise Exception if has_avoir === true or prevent_refund?
|
||||
avoir = Avoir.new(self.dup.attributes)
|
||||
raise Exception if refunded? === true || prevent_refund?
|
||||
|
||||
avoir = Avoir.new(dup.attributes)
|
||||
avoir.type = 'Avoir'
|
||||
avoir.attributes = attrs
|
||||
avoir.reference = nil
|
||||
@ -142,15 +146,15 @@ class Invoice < ActiveRecord::Base
|
||||
paid_items = 0
|
||||
refund_items = 0
|
||||
invoice_items.each do |ii|
|
||||
paid_items += 1 unless ii.amount == 0
|
||||
if attrs[:invoice_items_ids].include? ii.id # list of items to refund (partial refunds)
|
||||
raise Exception if ii.invoice_item # cannot refund an item that was already refunded
|
||||
refund_items += 1 unless ii.amount == 0
|
||||
avoir_ii = avoir.invoice_items.build(ii.dup.attributes)
|
||||
avoir_ii.created_at = avoir.avoir_date
|
||||
avoir_ii.invoice_item_id = ii.id
|
||||
avoir.total += avoir_ii.amount
|
||||
end
|
||||
paid_items += 1 unless ii.amount.zero?
|
||||
next unless attrs[:invoice_items_ids].include? ii.id # list of items to refund (partial refunds)
|
||||
raise Exception if ii.invoice_item # cannot refund an item that was already refunded
|
||||
|
||||
refund_items += 1 unless ii.amount.zero?
|
||||
avoir_ii = avoir.invoice_items.build(ii.dup.attributes)
|
||||
avoir_ii.created_at = avoir.avoir_date
|
||||
avoir_ii.invoice_item_id = ii.id
|
||||
avoir.total += avoir_ii.amount
|
||||
end
|
||||
# handle coupon
|
||||
unless avoir.coupon_id.nil?
|
||||
@ -167,9 +171,9 @@ class Invoice < ActiveRecord::Base
|
||||
avoir
|
||||
end
|
||||
|
||||
def is_subscription_invoice?
|
||||
def subscription_invoice?
|
||||
invoice_items.each do |ii|
|
||||
return true if ii.subscription and !ii.subscription.expired?
|
||||
return true if ii.subscription && !ii.subscription.expired?
|
||||
end
|
||||
false
|
||||
end
|
||||
@ -178,7 +182,7 @@ class Invoice < ActiveRecord::Base
|
||||
# Test if the current invoice has been refund, totally or partially.
|
||||
# @return {Boolean|'partial'}, true means fully refund, false means not refunded
|
||||
##
|
||||
def has_avoir
|
||||
def refunded?
|
||||
if avoir
|
||||
invoice_items.each do |item|
|
||||
return 'partial' unless item.invoice_item
|
||||
@ -195,7 +199,7 @@ class Invoice < ActiveRecord::Base
|
||||
# @return {Boolean}
|
||||
##
|
||||
def prevent_refund?
|
||||
if invoiced_type == 'Reservation' and invoiced.reservable_type == 'Training'
|
||||
if invoiced_type == 'Reservation' && invoiced.reservable_type == 'Training'
|
||||
user.trainings.include?(invoiced.reservable_id)
|
||||
else
|
||||
false
|
||||
@ -204,13 +208,15 @@ class Invoice < ActiveRecord::Base
|
||||
|
||||
# get amount total paid
|
||||
def amount_paid
|
||||
total - (wallet_amount ? wallet_amount : 0)
|
||||
total - (wallet_amount || 0)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_and_send_invoice
|
||||
unless Rails.env.test?
|
||||
puts "Creating an InvoiceWorker job to generate the following invoice: id(#{id}), invoiced_id(#{invoiced_id}), invoiced_type(#{invoiced_type}), user_id(#{user_id})"
|
||||
puts "Creating an InvoiceWorker job to generate the following invoice: id(#{id}), invoiced_id(#{invoiced_id}), " \
|
||||
"invoiced_type(#{invoiced_type}), user_id(#{user_id})"
|
||||
end
|
||||
InvoiceWorker.perform_async(id, user&.subscription&.expired_at)
|
||||
end
|
||||
@ -233,21 +239,21 @@ class Invoice < ActiveRecord::Base
|
||||
##
|
||||
def number_of_invoices(range)
|
||||
case range.to_s
|
||||
when 'day'
|
||||
start = DateTime.current.beginning_of_day
|
||||
ending = DateTime.current.end_of_day
|
||||
when 'month'
|
||||
start = DateTime.current.beginning_of_month
|
||||
ending = DateTime.current.end_of_month
|
||||
when 'year'
|
||||
start = DateTime.current.beginning_of_year
|
||||
ending = DateTime.current.end_of_year
|
||||
else
|
||||
return self.id
|
||||
end
|
||||
if defined? start and defined? ending
|
||||
Invoice.where('created_at >= :start_date AND created_at < :end_date', {start_date: start, end_date: ending}).length
|
||||
when 'day'
|
||||
start = DateTime.current.beginning_of_day
|
||||
ending = DateTime.current.end_of_day
|
||||
when 'month'
|
||||
start = DateTime.current.beginning_of_month
|
||||
ending = DateTime.current.end_of_month
|
||||
when 'year'
|
||||
start = DateTime.current.beginning_of_year
|
||||
ending = DateTime.current.end_of_year
|
||||
else
|
||||
return id
|
||||
end
|
||||
return Invoice.count unless defined? start && defined? ending
|
||||
|
||||
Invoice.where('created_at >= :start_date AND created_at < :end_date', start_date: start, end_date: ending).length
|
||||
end
|
||||
|
||||
end
|
||||
|
10
app/policies/accounting_period_policy.rb
Normal file
10
app/policies/accounting_period_policy.rb
Normal file
@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Check the access policies for API::AccountingPeriodsController
|
||||
class AccountingPeriodPolicy < ApplicationPolicy
|
||||
%w[index show create last_closing_end].each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
end
|
||||
end
|
||||
end
|
18
app/services/accounting_period_service.rb
Normal file
18
app/services/accounting_period_service.rb
Normal file
@ -0,0 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides methods for accessing AccountingPeriods properties
|
||||
class AccountingPeriodService
|
||||
|
||||
def self.find_last_period
|
||||
AccountingPeriod.where(end_at: AccountingPeriod.select('max(end_at)')).first
|
||||
end
|
||||
|
||||
def self.all_periods_with_users
|
||||
AccountingPeriod.joins("INNER JOIN #{User.arel_table.name} ON users.id = accounting_periods.closed_by
|
||||
INNER JOIN #{Profile.arel_table.name} ON profiles.user_id = users.id")
|
||||
.select("#{AccountingPeriod.arel_table.name}.*,
|
||||
#{Profile.arel_table.name}.first_name,
|
||||
#{Profile.arel_table.name}.last_name")
|
||||
.order('start_at DESC')
|
||||
end
|
||||
end
|
62
app/services/invoices_service.rb
Normal file
62
app/services/invoices_service.rb
Normal file
@ -0,0 +1,62 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides methods for accessing Invoices resources and properties
|
||||
class InvoicesService
|
||||
# return a paginated list of invoices, ordered by the given criterion and optionally filtered
|
||||
# @param order_key {string} any column from invoices or joined a table
|
||||
# @param direction {string} 'ASC' or 'DESC', linked to order_key
|
||||
# @param page {number} page number, used to paginate results
|
||||
# @param size {number} number of items per page
|
||||
# @param filters {Hash} allowed filters: number, customer, date.
|
||||
def self.list(order_key, direction, page, size, filters = {})
|
||||
invoices = Invoice.includes(:avoir, :invoiced, invoice_items: %i[subscription invoice_item], user: %i[profile trainings])
|
||||
.joins(user: :profile)
|
||||
.order("#{order_key} #{direction}")
|
||||
.page(page)
|
||||
.per(size)
|
||||
|
||||
|
||||
if filters[:number].size.positive?
|
||||
invoices = invoices.where(
|
||||
'invoices.reference LIKE :search',
|
||||
search: "#{filters[:number]}%"
|
||||
)
|
||||
end
|
||||
if filters[:customer].size.positive?
|
||||
# ILIKE => PostgreSQL case-insensitive LIKE
|
||||
invoices = invoices.where(
|
||||
'profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search',
|
||||
search: "%#{filters[:customer]}%"
|
||||
)
|
||||
end
|
||||
unless filters[:date].nil?
|
||||
invoices = invoices.where(
|
||||
"date_trunc('day', invoices.created_at) = :search",
|
||||
search: "%#{DateTime.iso8601(filters[:date]).to_time.to_date}%"
|
||||
)
|
||||
end
|
||||
|
||||
invoices
|
||||
end
|
||||
|
||||
# Parse the order_by clause provided by JS client from '-column' form to SQL compatible form
|
||||
# @param order_by {string} expected form: 'column' or '-column'
|
||||
def self.parse_order(order_by)
|
||||
direction = (order_by[0] == '-' ? 'DESC' : 'ASC')
|
||||
key = (order_by[0] == '-' ? order_by[1, order_by.size] : order_by)
|
||||
|
||||
order_key = case key
|
||||
when 'reference'
|
||||
'invoices.reference'
|
||||
when 'date'
|
||||
'invoices.created_at'
|
||||
when 'total'
|
||||
'invoices.total'
|
||||
when 'name'
|
||||
'profiles.first_name'
|
||||
else
|
||||
'invoices.id'
|
||||
end
|
||||
{ direction: direction, order_key: order_key }
|
||||
end
|
||||
end
|
17
app/validators/closed_period_validator.rb
Normal file
17
app/validators/closed_period_validator.rb
Normal file
@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Validates the current invoice is not generated within a closed accounting period
|
||||
class ClosedPeriodValidator < ActiveModel::Validator
|
||||
def validate(record)
|
||||
date = if record.is_a?(Avoir)
|
||||
record.avoir_date
|
||||
else
|
||||
DateTime.now
|
||||
end
|
||||
|
||||
|
||||
AccountingPeriod.all.each do |period|
|
||||
record.errors[:date] << I18n.t('errors.messages.in_closed_period') if date >= period.start_at && date <= period.end_at
|
||||
end
|
||||
end
|
||||
end
|
12
app/validators/date_range_validator.rb
Normal file
12
app/validators/date_range_validator.rb
Normal file
@ -0,0 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Validates that start_at is same or before end_at in the given record
|
||||
class DateRangeValidator < ActiveModel::Validator
|
||||
def validate(record)
|
||||
the_end = record.start_at
|
||||
the_start = record.end_at
|
||||
return unless the_end.present? && the_end >= the_start
|
||||
|
||||
record.errors[:end_at] << "The end date can't be before the start date. Pick a date after #{the_start}"
|
||||
end
|
||||
end
|
21
app/validators/period_overlap_validator.rb
Normal file
21
app/validators/period_overlap_validator.rb
Normal file
@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Validates the current accounting period does not overlap an existing one
|
||||
class PeriodOverlapValidator < ActiveModel::Validator
|
||||
def validate(record)
|
||||
the_end = record.end_at
|
||||
the_start = record.start_at
|
||||
|
||||
AccountingPeriod.all.each do |period|
|
||||
if the_start >= period.start_at && the_start <= period.end_at
|
||||
record.errors[:start_at] << I18n.t('errors.messages.cannot_overlap')
|
||||
end
|
||||
if the_end >= period.start_at && the_end <= period.end_at
|
||||
record.errors[:end_at] << I18n.t('errors.messages.cannot_overlap')
|
||||
end
|
||||
if period.start_at >= the_start && period.end_at <= the_end
|
||||
record.errors[:end_at] << I18n.t('errors.messages.cannot_encompass')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
6
app/views/api/accounting_periods/index.json.jbuilder
Normal file
6
app/views/api/accounting_periods/index.json.jbuilder
Normal file
@ -0,0 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.array!(@accounting_periods) do |ap|
|
||||
json.extract! ap, :id, :start_at, :end_at, :closed_at, :closed_by, :created_at
|
||||
json.user_name "#{ap.first_name} #{ap.last_name}"
|
||||
end
|
@ -0,0 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.last_end_date @last_end
|
3
app/views/api/accounting_periods/show.json.jbuilder
Normal file
3
app/views/api/accounting_periods/show.json.jbuilder
Normal file
@ -0,0 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.extract! @accounting_period, :id, :start_at, :end_at, :closed_at, :closed_by, :created_at
|
@ -3,9 +3,9 @@ json.array!(@invoices) do |invoice|
|
||||
json.total (invoice.total / 100.00)
|
||||
json.url invoice_url(invoice, format: :json)
|
||||
json.name invoice.user.profile.full_name
|
||||
json.has_avoir invoice.has_avoir
|
||||
json.has_avoir invoice.refunded?
|
||||
json.is_avoir invoice.is_a?(Avoir)
|
||||
json.is_subscription_invoice invoice.is_subscription_invoice?
|
||||
json.is_subscription_invoice invoice.subscription_invoice?
|
||||
json.stripe invoice.stp_invoice_id?
|
||||
json.date invoice.is_a?(Avoir) ? invoice.avoir_date : invoice.created_at
|
||||
json.prevent_refund invoice.prevent_refund?
|
||||
|
@ -6,10 +6,10 @@ json.array!(@invoices) do |invoice|
|
||||
json.total (invoice.total / 100.00)
|
||||
json.url invoice_url(invoice, format: :json)
|
||||
json.name invoice.user.profile.full_name
|
||||
json.has_avoir invoice.has_avoir
|
||||
json.has_avoir invoice.refunded?
|
||||
json.is_avoir invoice.is_a?(Avoir)
|
||||
json.is_subscription_invoice invoice.is_subscription_invoice?
|
||||
json.is_subscription_invoice invoice.subscription_invoice?
|
||||
json.stripe invoice.stp_invoice_id?
|
||||
json.date invoice.is_a?(Avoir) ? invoice.avoir_date : invoice.created_at
|
||||
json.prevent_refund invoice.prevent_refund?
|
||||
end
|
||||
end
|
||||
|
@ -1,9 +1,9 @@
|
||||
json.extract! @invoice, :id, :created_at, :reference, :invoiced_type, :user_id, :avoir_date, :description
|
||||
json.total (@invoice.total / 100.00)
|
||||
json.name @invoice.user.profile.full_name
|
||||
json.has_avoir @invoice.has_avoir
|
||||
json.has_avoir @invoice.refunded?
|
||||
json.is_avoir @invoice.is_a?(Avoir)
|
||||
json.is_subscription_invoice @invoice.is_subscription_invoice?
|
||||
json.is_subscription_invoice @invoice.subscription_invoice?
|
||||
json.stripe @invoice.stp_invoice_id?
|
||||
json.date @invoice.is_a?(Avoir) ? @invoice.avoir_date : @invoice.created_at
|
||||
json.items @invoice.invoice_items do |item|
|
||||
|
49
app/views/archive/_accounting.json.jbuilder
Normal file
49
app/views/archive/_accounting.json.jbuilder
Normal file
@ -0,0 +1,49 @@
|
||||
json.array!(invoices) do |invoice|
|
||||
json.extract! invoice, :id, :stp_invoice_id, :created_at, :reference
|
||||
json.total number_to_currency(invoice.total / 100.0)
|
||||
json.invoiced do
|
||||
json.type invoice.invoiced_type
|
||||
json.id invoice.invoiced_id
|
||||
if invoice.invoiced_type == Subscription.name
|
||||
json.extract! invoice.invoiced, :stp_subscription_id, :created_at, :expiration_date, :canceled_at
|
||||
json.plan do
|
||||
json.extract! invoice.invoiced.plan, :id, :base_name, :interval, :interval_count, :stp_plan_id, :is_rolling
|
||||
json.group do
|
||||
json.extract! invoice.invoiced.plan.group, :id, :name
|
||||
end
|
||||
end
|
||||
elsif invoice.invoiced_type == Reservation.name
|
||||
json.extract! invoice.invoiced, :created_at, :stp_invoice_id
|
||||
json.reservable do
|
||||
json.type invoice.invoiced.reservable_type
|
||||
json.id invoice.invoiced.reservable_id
|
||||
if [Training.name, Machine.name, Space.name].include?(invoice.invoiced.reservable_type) &&
|
||||
!invoice.invoiced.reservable.nil?
|
||||
json.extract! invoice.invoiced.reservable, :name, :created_at
|
||||
elsif invoice.invoiced.reservable_type == Event.name && !invoice.invoiced.reservable.nil?
|
||||
json.extract! invoice.invoiced.reservable, :title, :created_at
|
||||
json.prices do
|
||||
json.standard_price number_to_currency(invoice.invoiced.reservable.amount / 100.0)
|
||||
json.other_prices invoice.invoiced.reservable.event_price_categories do |price|
|
||||
json.amount number_to_currency(price.amount / 100.0)
|
||||
json.price_category do
|
||||
json.extract! price.price_category, :id, :name, :created_at
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
json.user do
|
||||
json.extract! invoice.user, :id, :email, :created_at
|
||||
json.profile do
|
||||
json.extract! invoice.user.profile, :id, :first_name, :last_name, :birthday, :phone
|
||||
json.gender invoice.user.profile.gender ? 'male' : 'female'
|
||||
end
|
||||
end
|
||||
json.invoice_items invoice.invoice_items do |item|
|
||||
json.extract! item, :id, :stp_invoice_item_id, :created_at, :description
|
||||
json.amount number_to_currency(item.amount / 100.0)
|
||||
end
|
||||
end
|
@ -282,115 +282,141 @@ en:
|
||||
subscription_successfully_changed: "Subscription successfully changed."
|
||||
|
||||
invoices:
|
||||
# list of all invoices & invoicing parameters
|
||||
invoices: "Invoices"
|
||||
invoices_list: "Invoices list"
|
||||
filter_invoices: "Filter invoices"
|
||||
invoice_#_: "Invoice #:"
|
||||
customer_: "Customer:"
|
||||
date_: "Date:"
|
||||
invoice_#: "Invoice #"
|
||||
customer: "Customer"
|
||||
credit_note: "Credit note"
|
||||
display_more_invoices: "Display more invoices..."
|
||||
invoicing_settings: "Invoicing settings"
|
||||
change_logo: "Change logo"
|
||||
john_smith: "John Smith"
|
||||
john_smith@example_com: "jean.smith@example.com"
|
||||
invoice_reference_: "Invoice reference:"
|
||||
code_: "Code:"
|
||||
code_disabled: "Code disabled"
|
||||
order_#: "Order #:"
|
||||
invoice_issued_on_DATE_at_TIME: "Invoice issued on {{DATE}} at {{TIME}}" # angular interpolation
|
||||
object_reservation_of_john_smith_on_DATE_at_TIME: "Object: Reservation of John Smith on {{DATE}} at {{TIME}}" # angular interpolation
|
||||
order_summary: "Order summary:"
|
||||
details: "Details"
|
||||
amount: "Amount"
|
||||
machine_booking-3D_printer: "Machine booking - 3D printer"
|
||||
total_amount: "Total amount"
|
||||
total_including_all_taxes: "Total incl. all taxes"
|
||||
VAT_disabled: "VAT disabled"
|
||||
including_VAT: "Including VAT"
|
||||
including_total_excluding_taxes: "Including Total excl. taxes"
|
||||
including_amount_payed_on_ordering: "Including Amount payed on ordering"
|
||||
settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Settlement by debit card on {{DATE}} at {{TIME}}, for an amount of {{AMOUNT}}"
|
||||
important_notes: "Important notes"
|
||||
address_and_legal_information: "Address and legal information"
|
||||
invoice_reference: "Invoice reference"
|
||||
day: "Day"
|
||||
"#_of_invoice": "# of invoice"
|
||||
online_sales: "Online sales"
|
||||
wallet: "Wallet"
|
||||
refund: "Refund"
|
||||
documentation: "Documentation"
|
||||
2_digits_year_(eg_70): "2 digits year (eg. 70)"
|
||||
4_digits_year_(eg_1970): "4 digits year (eg. 1970)"
|
||||
month_number_(eg_1): "Month number (eg. 1)"
|
||||
2_digits_month_number_(eg_01): "2 digits month number (eg. 01)"
|
||||
3_characters_month_name_(eg_JAN): "3 characters month name (eg. JAN)"
|
||||
day_in_the_month_(eg_1): "Day in the month (eg. 1)"
|
||||
2_digits_day_in_the_month_(eg_01): "2 digits in the month (eg. 01)"
|
||||
(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day): "(n) digits, daily count of invoices (eg. ddd => 002 : 2nd invoice of the day)"
|
||||
(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month): "(n) digits, monthly count of invoices (eg. mmmm => 0012 : 12th invoice of the month)"
|
||||
(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year): "(n) digits, annual count of invoices (ex. yyyyyy => 000008 : 8th invoice of this year)"
|
||||
beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Beware: if the number exceed the specified length, it will be truncated by the left."
|
||||
(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order): "(n) digits, count of invoices (eg. nnnn => 0327 : 327th order)"
|
||||
(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day): "(n) digits, daily count of orders (eg. ddd => 002 : 2nd order of the day)"
|
||||
(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month): "(n) digits, monthly count of orders (eg. mmmm => 0012 : 12th order of the month)"
|
||||
(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year): "(n) digits, annual count of orders (ex. yyyyyy => 000008 : 8th order of this year)"
|
||||
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Add a notice regarding the online sales, only if the invoice is concerned."
|
||||
this_will_never_be_added_when_a_refund_notice_is_present: "This will never be added when a refund notice is present."
|
||||
(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe): '(eg. X[/VL] will add "/VL" to the invoices settled with stripe)'
|
||||
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Add a notice regarding refunds, only if the invoice is concerned."
|
||||
this_will_never_be_added_when_an_online_sales_notice_is_present: "This will never be added when an online sales notice is present."
|
||||
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ed. R[/A] will add "/A" to the refund invoices)'
|
||||
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Add a notice regarding the wallet, only if the invoice is concerned."
|
||||
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(eg. W[/PM] will add "/PM" to the invoices settled with wallet)'
|
||||
code: "Code"
|
||||
enable_the_code: "Enable the code"
|
||||
enabled: "Enabled"
|
||||
disabled: "Disabled"
|
||||
order_number: "Order number"
|
||||
elements: "Elements"
|
||||
VAT: "VAT"
|
||||
enable_VAT: "Enable VAT"
|
||||
VAT_rate: "VAT rate"
|
||||
refund_invoice_successfully_created: "Refund invoice successfully created."
|
||||
create_a_refund_on_this_invoice: "Create a refund on this invoice"
|
||||
creation_date_for_the_refund: "Creation date for the refund"
|
||||
creation_date_is_required: "Creation date is required."
|
||||
refund_mode: "Refund mode:"
|
||||
do_you_want_to_disable_the_user_s_subscription: "Do you want to disabled the user's subscription:"
|
||||
elements_to_refund: "Elements to refund"
|
||||
description_(optional): "Description (optional):"
|
||||
will_appear_on_the_refund_invoice: "Will appear on the refund invoice."
|
||||
none: "None" # grammar note: concordance with "payment mean"
|
||||
by_cash: "By cash"
|
||||
by_cheque: "By cheque"
|
||||
by_transfer: "By transfer"
|
||||
by_wallet: "By wallet"
|
||||
you_must_select_at_least_one_element_to_create_a_refund: "You must select at least one element, to create a refund."
|
||||
unable_to_create_the_refund: "Unable to create the refund"
|
||||
invoice_reference_successfully_saved: "Invoice reference successfully saved."
|
||||
an_error_occurred_while_saving_invoice_reference: "An error occurred while saving invoice reference."
|
||||
invoicing_code_succesfully_saved: "Invoicing code successfully saved."
|
||||
an_error_occurred_while_saving_the_invoicing_code: "An error occurred while saving the invoicing code."
|
||||
code_successfully_activated: "Code successfully activated."
|
||||
code_successfully_disabled: "Code successfully disabled."
|
||||
an_error_occurred_while_activating_the_invoicing_code: "An error occurred while activating the invoicing code."
|
||||
order_number_successfully_saved: "Order number successfully saved."
|
||||
an_error_occurred_while_saving_the_order_number: "An error occurred while saving the order number."
|
||||
VAT_rate_successfully_saved: "VAT rate successfully saved."
|
||||
an_error_occurred_while_saving_the_VAT_rate: "An error occurred while saving the VAT rate."
|
||||
VAT_successfully_activated: "VAT successfully activated."
|
||||
VAT_successfully_disabled: "VAT successfully disabled."
|
||||
an_error_occurred_while_activating_the_VAT: "An error occurred while activating the VAT."
|
||||
text_successfully_saved: "Text successfully saved."
|
||||
an_error_occurred_while_saving_the_text: "An error occurred while saving the text."
|
||||
address_and_legal_information_successfully_saved: "Address and legal information successfully saved."
|
||||
an_error_occurred_while_saving_the_address_and_the_legal_information: "An error occurred while saving the address and the legal information."
|
||||
logo_successfully_saved: "Logo successfully saved."
|
||||
an_error_occurred_while_saving_the_logo: "An error occurred while saving the logo."
|
||||
invoices:
|
||||
# list of all invoices & invoicing parameters
|
||||
invoices: "Invoices"
|
||||
invoices_list: "Invoices list"
|
||||
filter_invoices: "Filter invoices"
|
||||
invoice_#_: "Invoice #:"
|
||||
customer_: "Customer:"
|
||||
date_: "Date:"
|
||||
invoice_#: "Invoice #"
|
||||
date: "Date"
|
||||
price: "Price"
|
||||
customer: "Customer"
|
||||
download_the_invoice: "Download the invoice"
|
||||
download_the_credit_note: "Download the credit note"
|
||||
credit_note: "Credit note"
|
||||
display_more_invoices: "Display more invoices..."
|
||||
no_invoices_for_now: "No invoices for now."
|
||||
invoicing_settings: "Invoicing settings"
|
||||
change_logo: "Change logo"
|
||||
john_smith: "John Smith"
|
||||
john_smith@example_com: "jean.smith@example.com"
|
||||
invoice_reference_: "Invoice reference:"
|
||||
code_: "Code:"
|
||||
code_disabled: "Code disabled"
|
||||
order_#: "Order #:"
|
||||
invoice_issued_on_DATE_at_TIME: "Invoice issued on {{DATE}} at {{TIME}}" # angular interpolation
|
||||
object_reservation_of_john_smith_on_DATE_at_TIME: "Object: Reservation of John Smith on {{DATE}} at {{TIME}}" # angular interpolation
|
||||
order_summary: "Order summary:"
|
||||
details: "Details"
|
||||
amount: "Amount"
|
||||
machine_booking-3D_printer: "Machine booking - 3D printer"
|
||||
total_amount: "Total amount"
|
||||
total_including_all_taxes: "Total incl. all taxes"
|
||||
VAT_disabled: "VAT disabled"
|
||||
including_VAT: "Including VAT"
|
||||
including_total_excluding_taxes: "Including Total excl. taxes"
|
||||
including_amount_payed_on_ordering: "Including Amount payed on ordering"
|
||||
settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Settlement by debit card on {{DATE}} at {{TIME}}, for an amount of {{AMOUNT}}"
|
||||
important_notes: "Important notes"
|
||||
address_and_legal_information: "Address and legal information"
|
||||
invoice_reference: "Invoice reference"
|
||||
year: "Year"
|
||||
month: "Month"
|
||||
day: "Day"
|
||||
"#_of_invoice": "# of invoice"
|
||||
online_sales: "Online sales"
|
||||
wallet: "Wallet"
|
||||
refund: "Refund"
|
||||
model: "Model"
|
||||
documentation: "Documentation"
|
||||
2_digits_year_(eg_70): "2 digits year (eg. 70)"
|
||||
4_digits_year_(eg_1970): "4 digits year (eg. 1970)"
|
||||
month_number_(eg_1): "Month number (eg. 1)"
|
||||
2_digits_month_number_(eg_01): "2 digits month number (eg. 01)"
|
||||
3_characters_month_name_(eg_JAN): "3 characters month name (eg. JAN)"
|
||||
day_in_the_month_(eg_1): "Day in the month (eg. 1)"
|
||||
2_digits_day_in_the_month_(eg_01): "2 digits in the month (eg. 01)"
|
||||
(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day): "(n) digits, daily count of invoices (eg. ddd => 002 : 2nd invoice of the day)"
|
||||
(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month): "(n) digits, monthly count of invoices (eg. mmmm => 0012 : 12th invoice of the month)"
|
||||
(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year): "(n) digits, annual count of invoices (ex. yyyyyy => 000008 : 8th invoice of this year)"
|
||||
beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Beware: if the number exceed the specified length, it will be truncated by the left."
|
||||
(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order): "(n) digits, count of invoices (eg. nnnn => 0327 : 327th order)"
|
||||
(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day): "(n) digits, daily count of orders (eg. ddd => 002 : 2nd order of the day)"
|
||||
(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month): "(n) digits, monthly count of orders (eg. mmmm => 0012 : 12th order of the month)"
|
||||
(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year): "(n) digits, annual count of orders (ex. yyyyyy => 000008 : 8th order of this year)"
|
||||
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Add a notice regarding the online sales, only if the invoice is concerned."
|
||||
this_will_never_be_added_when_a_refund_notice_is_present: "This will never be added when a refund notice is present."
|
||||
(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe): '(eg. X[/VL] will add "/VL" to the invoices settled with stripe)'
|
||||
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Add a notice regarding refunds, only if the invoice is concerned."
|
||||
this_will_never_be_added_when_an_online_sales_notice_is_present: "This will never be added when an online sales notice is present."
|
||||
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ed. R[/A] will add "/A" to the refund invoices)'
|
||||
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Add a notice regarding the wallet, only if the invoice is concerned."
|
||||
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(eg. W[/PM] will add "/PM" to the invoices settled with wallet)'
|
||||
code: "Code"
|
||||
enable_the_code: "Enable the code"
|
||||
enabled: "Enabled"
|
||||
disabled: "Disabled"
|
||||
order_number: "Order number"
|
||||
elements: "Elements"
|
||||
VAT: "VAT"
|
||||
enable_VAT: "Enable VAT"
|
||||
VAT_rate: "VAT rate"
|
||||
refund_invoice_successfully_created: "Refund invoice successfully created."
|
||||
create_a_refund_on_this_invoice: "Create a refund on this invoice"
|
||||
creation_date_for_the_refund: "Creation date for the refund"
|
||||
creation_date_is_required: "Creation date is required."
|
||||
refund_mode: "Refund mode:"
|
||||
do_you_want_to_disable_the_user_s_subscription: "Do you want to disabled the user's subscription:"
|
||||
elements_to_refund: "Elements to refund"
|
||||
description: "Description"
|
||||
description_(optional): "Description (optional):"
|
||||
will_appear_on_the_refund_invoice: "Will appear on the refund invoice."
|
||||
none: "None" # grammar note: concordance with "payment mean"
|
||||
by_cash: "By cash"
|
||||
by_cheque: "By cheque"
|
||||
by_transfer: "By transfer"
|
||||
by_wallet: "By wallet"
|
||||
you_must_select_at_least_one_element_to_create_a_refund: "You must select at least one element, to create a refund."
|
||||
unable_to_create_the_refund: "Unable to create the refund"
|
||||
invoice_reference_successfully_saved: "Invoice reference successfully saved."
|
||||
an_error_occurred_while_saving_invoice_reference: "An error occurred while saving invoice reference."
|
||||
invoicing_code_succesfully_saved: "Invoicing code successfully saved."
|
||||
an_error_occurred_while_saving_the_invoicing_code: "An error occurred while saving the invoicing code."
|
||||
code_successfully_activated: "Code successfully activated."
|
||||
code_successfully_disabled: "Code successfully disabled."
|
||||
an_error_occurred_while_activating_the_invoicing_code: "An error occurred while activating the invoicing code."
|
||||
order_number_successfully_saved: "Order number successfully saved."
|
||||
an_error_occurred_while_saving_the_order_number: "An error occurred while saving the order number."
|
||||
VAT_rate_successfully_saved: "VAT rate successfully saved."
|
||||
an_error_occurred_while_saving_the_VAT_rate: "An error occurred while saving the VAT rate."
|
||||
VAT_successfully_activated: "VAT successfully activated."
|
||||
VAT_successfully_disabled: "VAT successfully disabled."
|
||||
an_error_occurred_while_activating_the_VAT: "An error occurred while activating the VAT."
|
||||
text_successfully_saved: "Text successfully saved."
|
||||
an_error_occurred_while_saving_the_text: "An error occurred while saving the text."
|
||||
address_and_legal_information_successfully_saved: "Address and legal information successfully saved."
|
||||
an_error_occurred_while_saving_the_address_and_the_legal_information: "An error occurred while saving the address and the legal information."
|
||||
logo_successfully_saved: "Logo successfully saved."
|
||||
an_error_occurred_while_saving_the_logo: "An error occurred while saving the logo."
|
||||
online_payment: "Online payment"
|
||||
close_accounting_period: "Close an accounting period"
|
||||
close_from_date: "Close from"
|
||||
start_date_is_required: "Start date is required"
|
||||
close_until_date: "Close until"
|
||||
end_date_is_required: "End date is required"
|
||||
previous_closings: "Previous closings"
|
||||
start_date: "From"
|
||||
end_date: "To"
|
||||
closed_at: "Closed at"
|
||||
closed_by: "By"
|
||||
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."
|
||||
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"
|
||||
|
||||
members:
|
||||
# management of users, labels, groups, and so on
|
||||
|
@ -282,115 +282,141 @@ es:
|
||||
subscription_successfully_changed: "Suscripción cambiada correctamente."
|
||||
|
||||
invoices:
|
||||
# list of all invoices & invoicing parameters
|
||||
invoices: "Facturas"
|
||||
invoices_list: "Lista de facturas"
|
||||
filter_invoices: "Filtrar facturas"
|
||||
invoice_#_: "Factura #:"
|
||||
customer_: "Cliente:"
|
||||
date_: "Fecha:"
|
||||
invoice_#: "Factura #"
|
||||
customer: "Cliente"
|
||||
credit_note: "Nota de crédito"
|
||||
display_more_invoices: "Mostrar más facturas..."
|
||||
invoicing_settings: "Configuración de facturación"
|
||||
change_logo: "Cambio de logotipo"
|
||||
john_smith: "John Smith"
|
||||
john_smith@example_com: "jean.smith@example.com"
|
||||
invoice_reference_: "Referencia de factura:"
|
||||
code_: "Código:"
|
||||
code_disabled: "Código inhabilitado"
|
||||
order_#: "Orden #:"
|
||||
invoice_issued_on_DATE_at_TIME: "Factura emitida el {{DATE}} a las {{TIME}}" # angular interpolation
|
||||
object_reservation_of_john_smith_on_DATE_at_TIME: "Objeto: Reserva de John Smith el {{DATE}} a las {{TIME}}" # angular interpolation
|
||||
order_summary: "Resumen del pedido:"
|
||||
details: "Detalles"
|
||||
amount: "Cantidad"
|
||||
machine_booking-3D_printer: "Reserva de la máquina- Impresora 3D"
|
||||
total_amount: "Cantidad total"
|
||||
total_including_all_taxes: "Total incl. todos los impuestos"
|
||||
VAT_disabled: "VAT disabled"
|
||||
including_VAT: "IVA desactivado"
|
||||
including_total_excluding_taxes: "Incluido Total excl. impuestos"
|
||||
including_amount_payed_on_ordering: "Incluido el monto pagado en el pedido"
|
||||
settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Liquidación por tarjeta de débito el {{DATE}} a las {{TIME}}, por una cantidad de {{AMOUNT}}"
|
||||
important_notes: "Notas importantes"
|
||||
address_and_legal_information: "Dirección e información legal"
|
||||
invoice_reference: "Referencia de factura"
|
||||
day: "Día"
|
||||
"#_of_invoice": "# de factura"
|
||||
online_sales: "Ventas en línea"
|
||||
wallet: "Cartera"
|
||||
refund: "Reembolso"
|
||||
documentation: "Documentación"
|
||||
2_digits_year_(eg_70): "2 dígitos del año (por ejemplo, 70)"
|
||||
4_digits_year_(eg_1970): "4 dígitos del año (por ejemplo, 70)"
|
||||
month_number_(eg_1): "Número del mes (por ejemplo, 1)"
|
||||
2_digits_month_number_(eg_01): "Número de mes de 2 dígitos (por ejemplo, 01)"
|
||||
3_characters_month_name_(eg_JAN): "3 caracteres nombre del mes (por ejemplo, ENE)"
|
||||
day_in_the_month_(eg_1): "Día del mes (por ejemplo, 1)"
|
||||
2_digits_day_in_the_month_(eg_01): "2 dígitos en el mes (por ejemplo, 01)"
|
||||
(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day): "(n) dígitos, cuenta diaria de facturas (por ejemplo, ddd => 002: 2ª factura del día)"
|
||||
(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month): "(n) dígitos, recuento mensual de facturas (por ejemplo, mmmm => 0012: 12ª factura del mes)"
|
||||
(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year): "(n) dígitos, recuento anual de facturas (ej. aaaaa => 000008: 8ª factura de este año)"
|
||||
beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Cuidado: si el número excede la longitud especificada, será aproximado por la izquierda."
|
||||
(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order): "(n) dígitos, cuenta diaria de órdenes (eg ddd => 002: segunda orden del día)"
|
||||
(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day): "((n) dígitos, cuenta diaria de órdenes (eg ddd => 002: segunda orden del día)"
|
||||
(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month): "(n) dígitos, recuento mensual de pedidos (por ejemplo, mmmm => 0012: 12º orden del mes)"
|
||||
(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year): "(n) dígitos, recuento anual de órdenes (ej: aaaaa => 000008: octava orden de este año)"
|
||||
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Añadir un aviso con respecto a las ventas en línea, sólo si la factura es de interés."
|
||||
this_will_never_be_added_when_a_refund_notice_is_present: "Esto nunca se agregará cuando se presente un aviso de reembolso."
|
||||
(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe): '(por ejemplo, X [/ VL] agregará "/ VL" a las facturas liquidadas con la raya)'
|
||||
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Añada un aviso con respecto a los reembolsos, sólo si la factura es de interés."
|
||||
this_will_never_be_added_when_an_online_sales_notice_is_present: "Esto nunca se agregará cuando un aviso de venta en línea está presente."
|
||||
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ed. R[/A] añadirá "/A" a las facturas de reembolso)'
|
||||
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Añadir un aviso con respecto a la cartera, sólo si la factura es de interés."
|
||||
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(eg. W[/PM] añadirá "/PM" a las facturas liquidadas con cartera)'
|
||||
code: "Código"
|
||||
enable_the_code: "Habilitar el código"
|
||||
enabled: "Habilitado"
|
||||
disabled: "Desactivado"
|
||||
order_number: "Número de orden"
|
||||
elements: "Elementos"
|
||||
VAT: "IVA"
|
||||
enable_VAT: "Habilitar IVA"
|
||||
VAT_rate: "Ratio IVA"
|
||||
refund_invoice_successfully_created: "Factura de reembolso creada correctamente."
|
||||
create_a_refund_on_this_invoice: "Crear un reembolso en esta factura"
|
||||
creation_date_for_the_refund: "Fecha de creación del reembolso"
|
||||
creation_date_is_required: "Se requiere la fecha de creación."
|
||||
refund_mode: "Modo de reembolso:"
|
||||
do_you_want_to_disable_the_user_s_subscription: "¿Quieres inhabilitar la suscripción del usuario?:"
|
||||
elements_to_refund: "Elementos a reembolsar"
|
||||
description_(optional): "Descripción (opcional):"
|
||||
will_appear_on_the_refund_invoice: "Aparecerá en la factura de reembolso."
|
||||
none: "Nada" # grammar note: concordancia con "medio de pago""
|
||||
by_cash: "En efectivo"
|
||||
by_cheque: "Mediante cheque"
|
||||
by_transfer: "Por transferencia"
|
||||
by_wallet: "Por cartera"
|
||||
you_must_select_at_least_one_element_to_create_a_refund: "Debe seleccionar al menos un elemento, para crear un reembolso."
|
||||
unable_to_create_the_refund: "No se puede crear el reembolso"
|
||||
invoice_reference_successfully_saved: "Referencia de factura guardada correctamente."
|
||||
an_error_occurred_while_saving_invoice_reference: "Se ha producido un error al guardar la referencia de la factura."
|
||||
invoicing_code_succesfully_saved: "Código de facturación guardado correctamente."
|
||||
an_error_occurred_while_saving_the_invoicing_code: "Se ha producido un error al guardar el código de facturación.."
|
||||
code_successfully_activated: "Código activado correctamente."
|
||||
code_successfully_disabled: "Código deshabilitado correctamente."
|
||||
an_error_occurred_while_activating_the_invoicing_code: "Se ha producido un error al activar el código de facturación."
|
||||
order_number_successfully_saved: "Número de pedido guardado correctamente."
|
||||
an_error_occurred_while_saving_the_order_number: "Se ha producido un error al guardar el número de orden."
|
||||
VAT_rate_successfully_saved: "VAT rate successfully saved." # translation_missing
|
||||
an_error_occurred_while_saving_the_VAT_rate: "La tasa de IVA se ha guardado correctamente."
|
||||
VAT_successfully_activated: "IVA activado correctamente."
|
||||
VAT_successfully_disabled: "IVA desactivado correctamente."
|
||||
an_error_occurred_while_activating_the_VAT: "Se ha producido un error al activar el IVA."
|
||||
text_successfully_saved: "Texto guardado correctamente."
|
||||
an_error_occurred_while_saving_the_text: "Se ha producido un error al guardar el texto."
|
||||
address_and_legal_information_successfully_saved: "Dirección e información legal guardada correctamente."
|
||||
an_error_occurred_while_saving_the_address_and_the_legal_information: "Se ha producido un error al guardar la dirección y la información legal."
|
||||
logo_successfully_saved: "Logo guardado correctamente."
|
||||
an_error_occurred_while_saving_the_logo: "Se ha producido un error al guardar el logotipo.."
|
||||
invoices:
|
||||
# list of all invoices & invoicing parameters
|
||||
invoices: "Facturas"
|
||||
invoices_list: "Lista de facturas"
|
||||
filter_invoices: "Filtrar facturas"
|
||||
invoice_#_: "Factura #:"
|
||||
customer_: "Cliente:"
|
||||
date_: "Fecha:"
|
||||
invoice_#: "Factura #"
|
||||
date: "Día"
|
||||
price: "Precio"
|
||||
customer: "Cliente"
|
||||
download_the_invoice: "Descargar factura"
|
||||
download_the_credit_note: "Descargar nota de crédito"
|
||||
credit_note: "Nota de crédito"
|
||||
display_more_invoices: "Mostrar más facturas..."
|
||||
no_invoices_for_now: "Sin facturas por ahora."
|
||||
invoicing_settings: "Configuración de facturación"
|
||||
change_logo: "Cambio de logotipo"
|
||||
john_smith: "John Smith"
|
||||
john_smith@example_com: "jean.smith@example.com"
|
||||
invoice_reference_: "Referencia de factura:"
|
||||
code_: "Código:"
|
||||
code_disabled: "Código inhabilitado"
|
||||
order_#: "Orden #:"
|
||||
invoice_issued_on_DATE_at_TIME: "Factura emitida el {{DATE}} a las {{TIME}}" # angular interpolation
|
||||
object_reservation_of_john_smith_on_DATE_at_TIME: "Objeto: Reserva de John Smith el {{DATE}} a las {{TIME}}" # angular interpolation
|
||||
order_summary: "Resumen del pedido:"
|
||||
details: "Detalles"
|
||||
amount: "Cantidad"
|
||||
machine_booking-3D_printer: "Reserva de la máquina- Impresora 3D"
|
||||
total_amount: "Cantidad total"
|
||||
total_including_all_taxes: "Total incl. todos los impuestos"
|
||||
VAT_disabled: "VAT disabled"
|
||||
including_VAT: "IVA desactivado"
|
||||
including_total_excluding_taxes: "Incluido Total excl. impuestos"
|
||||
including_amount_payed_on_ordering: "Incluido el monto pagado en el pedido"
|
||||
settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Liquidación por tarjeta de débito el {{DATE}} a las {{TIME}}, por una cantidad de {{AMOUNT}}"
|
||||
important_notes: "Notas importantes"
|
||||
address_and_legal_information: "Dirección e información legal"
|
||||
invoice_reference: "Referencia de factura"
|
||||
year: "Año"
|
||||
month: "Mes"
|
||||
day: "Día"
|
||||
"#_of_invoice": "# de factura"
|
||||
online_sales: "Ventas en línea"
|
||||
wallet: "Cartera"
|
||||
refund: "Reembolso"
|
||||
model: "Modelo"
|
||||
documentation: "Documentación"
|
||||
2_digits_year_(eg_70): "2 dígitos del año (por ejemplo, 70)"
|
||||
4_digits_year_(eg_1970): "4 dígitos del año (por ejemplo, 70)"
|
||||
month_number_(eg_1): "Número del mes (por ejemplo, 1)"
|
||||
2_digits_month_number_(eg_01): "Número de mes de 2 dígitos (por ejemplo, 01)"
|
||||
3_characters_month_name_(eg_JAN): "3 caracteres nombre del mes (por ejemplo, ENE)"
|
||||
day_in_the_month_(eg_1): "Día del mes (por ejemplo, 1)"
|
||||
2_digits_day_in_the_month_(eg_01): "2 dígitos en el mes (por ejemplo, 01)"
|
||||
(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day): "(n) dígitos, cuenta diaria de facturas (por ejemplo, ddd => 002: 2ª factura del día)"
|
||||
(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month): "(n) dígitos, recuento mensual de facturas (por ejemplo, mmmm => 0012: 12ª factura del mes)"
|
||||
(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year): "(n) dígitos, recuento anual de facturas (ej. aaaaa => 000008: 8ª factura de este año)"
|
||||
beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Cuidado: si el número excede la longitud especificada, será aproximado por la izquierda."
|
||||
(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order): "(n) dígitos, cuenta diaria de órdenes (eg ddd => 002: segunda orden del día)"
|
||||
(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day): "((n) dígitos, cuenta diaria de órdenes (eg ddd => 002: segunda orden del día)"
|
||||
(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month): "(n) dígitos, recuento mensual de pedidos (por ejemplo, mmmm => 0012: 12º orden del mes)"
|
||||
(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year): "(n) dígitos, recuento anual de órdenes (ej: aaaaa => 000008: octava orden de este año)"
|
||||
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Añadir un aviso con respecto a las ventas en línea, sólo si la factura es de interés."
|
||||
this_will_never_be_added_when_a_refund_notice_is_present: "Esto nunca se agregará cuando se presente un aviso de reembolso."
|
||||
(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe): '(por ejemplo, X [/ VL] agregará "/ VL" a las facturas liquidadas con la raya)'
|
||||
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Añada un aviso con respecto a los reembolsos, sólo si la factura es de interés."
|
||||
this_will_never_be_added_when_an_online_sales_notice_is_present: "Esto nunca se agregará cuando un aviso de venta en línea está presente."
|
||||
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ed. R[/A] añadirá "/A" a las facturas de reembolso)'
|
||||
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Añadir un aviso con respecto a la cartera, sólo si la factura es de interés."
|
||||
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(eg. W[/PM] añadirá "/PM" a las facturas liquidadas con cartera)'
|
||||
code: "Código"
|
||||
enable_the_code: "Habilitar el código"
|
||||
enabled: "Habilitado"
|
||||
disabled: "Desactivado"
|
||||
order_number: "Número de orden"
|
||||
elements: "Elementos"
|
||||
VAT: "IVA"
|
||||
enable_VAT: "Habilitar IVA"
|
||||
VAT_rate: "Ratio IVA"
|
||||
refund_invoice_successfully_created: "Factura de reembolso creada correctamente."
|
||||
create_a_refund_on_this_invoice: "Crear un reembolso en esta factura"
|
||||
creation_date_for_the_refund: "Fecha de creación del reembolso"
|
||||
creation_date_is_required: "Se requiere la fecha de creación."
|
||||
refund_mode: "Modo de reembolso:"
|
||||
do_you_want_to_disable_the_user_s_subscription: "¿Quieres inhabilitar la suscripción del usuario?:"
|
||||
elements_to_refund: "Elementos a reembolsar"
|
||||
description: "Descripción"
|
||||
description_(optional): "Descripción (opcional):"
|
||||
will_appear_on_the_refund_invoice: "Aparecerá en la factura de reembolso."
|
||||
none: "Nada" # grammar note: concordancia con "medio de pago""
|
||||
by_cash: "En efectivo"
|
||||
by_cheque: "Mediante cheque"
|
||||
by_transfer: "Por transferencia"
|
||||
by_wallet: "Por cartera"
|
||||
you_must_select_at_least_one_element_to_create_a_refund: "Debe seleccionar al menos un elemento, para crear un reembolso."
|
||||
unable_to_create_the_refund: "No se puede crear el reembolso"
|
||||
invoice_reference_successfully_saved: "Referencia de factura guardada correctamente."
|
||||
an_error_occurred_while_saving_invoice_reference: "Se ha producido un error al guardar la referencia de la factura."
|
||||
invoicing_code_succesfully_saved: "Código de facturación guardado correctamente."
|
||||
an_error_occurred_while_saving_the_invoicing_code: "Se ha producido un error al guardar el código de facturación.."
|
||||
code_successfully_activated: "Código activado correctamente."
|
||||
code_successfully_disabled: "Código deshabilitado correctamente."
|
||||
an_error_occurred_while_activating_the_invoicing_code: "Se ha producido un error al activar el código de facturación."
|
||||
order_number_successfully_saved: "Número de pedido guardado correctamente."
|
||||
an_error_occurred_while_saving_the_order_number: "Se ha producido un error al guardar el número de orden."
|
||||
VAT_rate_successfully_saved: "VAT rate successfully saved." # translation_missing
|
||||
an_error_occurred_while_saving_the_VAT_rate: "La tasa de IVA se ha guardado correctamente."
|
||||
VAT_successfully_activated: "IVA activado correctamente."
|
||||
VAT_successfully_disabled: "IVA desactivado correctamente."
|
||||
an_error_occurred_while_activating_the_VAT: "Se ha producido un error al activar el IVA."
|
||||
text_successfully_saved: "Texto guardado correctamente."
|
||||
an_error_occurred_while_saving_the_text: "Se ha producido un error al guardar el texto."
|
||||
address_and_legal_information_successfully_saved: "Dirección e información legal guardada correctamente."
|
||||
an_error_occurred_while_saving_the_address_and_the_legal_information: "Se ha producido un error al guardar la dirección y la información legal."
|
||||
logo_successfully_saved: "Logo guardado correctamente."
|
||||
an_error_occurred_while_saving_the_logo: "Se ha producido un error al guardar el logotipo.."
|
||||
online_payment: "Pago online"
|
||||
close_accounting_period: "Close an accounting period" # translation_missing
|
||||
close_from_date: "Close from" # translation_missing
|
||||
start_date_is_required: "Start date is required" # translation_missing
|
||||
close_until_date: "Close until" # translation_missing
|
||||
end_date_is_required: "End date is required" # translation_missing
|
||||
previous_closings: "Previous closings" # translation_missing
|
||||
start_date: "From" # translation_missing
|
||||
end_date: "To" # translation_missing
|
||||
closed_at: "Closed at" # translation_missing
|
||||
closed_by: "By" # translation_missing
|
||||
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." # 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
|
||||
|
||||
members:
|
||||
# management of users, labels, groups, and so on
|
||||
@ -591,7 +617,7 @@ es:
|
||||
terms_of_service_(TOS): "Términos de servicio (TOS)"
|
||||
customize_the_graphics: "Personalizar los gráficos"
|
||||
for_an_optimal_rendering_the_logo_image_must_be_at_the_PNG_format_with_a_transparent_background_and_with_an_aspect_ratio_3.5_times_wider_than_the_height: "Para una representación óptima, la imagen del logotipo debe estar en el formato PNG con un fondo transparente y una relación de aspecto 3,5 más ancha que la altura."
|
||||
concerning_the_favicon_it_must_be_at_ICO_format_with_a_size_of_16x16_pixels: "En cuanto al favicon, debe estar en formato ICO con un tamaño de 16x16 píxeles."
|
||||
concerning_the_favicon_it_must_be_at_ICO_format_with_a_size_of_16x16_pixels: "En cuanto al favicon, debe estar en formato ICO con un tamaño de 16x16 píxeles."
|
||||
remember_to_refresh_the_page_for_the_changes_to_take_effect: "Recuerde actualizar la página para que los cambios surtan efecto."
|
||||
logo_(white_background): "Logo (fondo blanco)"
|
||||
change_the_logo: "Cambiar el logotipo"
|
||||
|
@ -282,115 +282,141 @@ fr:
|
||||
subscription_successfully_changed: "Modification de l'abonnement réussie."
|
||||
|
||||
invoices:
|
||||
# liste de toutes les factures & paramètres de facturation
|
||||
invoices: "Factures"
|
||||
invoices_list: "Liste des factures"
|
||||
filter_invoices: "Filtrer les factures"
|
||||
invoice_#_: "Facture n° :"
|
||||
customer_: "Client :"
|
||||
date_: "Date :"
|
||||
invoice_#: "Facture n°"
|
||||
customer: "Client"
|
||||
credit_note: "Avoir"
|
||||
display_more_invoices: "Afficher plus de factures ..."
|
||||
invoicing_settings: "Paramètres de facturation"
|
||||
change_logo: "Changer le logo"
|
||||
john_smith: "Jean Dupont"
|
||||
john_smith@example_com: "jean.dupont@example.com"
|
||||
invoice_reference_: "Référence facture :"
|
||||
code_: "Code :"
|
||||
code_disabled: "Code désactivé"
|
||||
order_#: "N° Commande :"
|
||||
invoice_issued_on_DATE_at_TIME: "Facture éditée le {{DATE}} à {{TIME}}" # angular interpolation
|
||||
object_reservation_of_john_smith_on_DATE_at_TIME: "Objet : Réservation de Jean Dupont le {{DATE}} à {{TIME}}" # angular interpolation
|
||||
order_summary: "Récapitulatif de la commande :"
|
||||
details: "Détails"
|
||||
amount: "Montant"
|
||||
machine_booking-3D_printer: "Réservation Machine - Imprimante 3D"
|
||||
total_amount: "Montant total"
|
||||
total_including_all_taxes: "Total TTC"
|
||||
VAT_disabled: "TVA désactivée"
|
||||
including_VAT: "Dont TVA"
|
||||
including_total_excluding_taxes: "Dont total HT"
|
||||
including_amount_payed_on_ordering: "Dont montant payé à la commande"
|
||||
settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Règlement effectué par carte bancaire le {{DATE}} à {{TIME}}, pour un montant de {{AMOUNT}}"
|
||||
important_notes: "Informations importantes"
|
||||
address_and_legal_information: "Adresse et informations légales"
|
||||
invoice_reference: "Référence facture"
|
||||
day: "Jour"
|
||||
"#_of_invoice": "N° de facture"
|
||||
online_sales: "Vente en ligne"
|
||||
wallet: "Porte-monnaie"
|
||||
refund: "Remboursement"
|
||||
documentation: "Documentation"
|
||||
2_digits_year_(eg_70): "Année sur 2 chiffres (ex. 70)"
|
||||
4_digits_year_(eg_1970): "Année sur 4 chiffres (ex. 1970)"
|
||||
month_number_(eg_1): "Numéro du mois (ex. 1)"
|
||||
2_digits_month_number_(eg_01): "Numéro du mois sur 2 chiffres (ex. 01)"
|
||||
3_characters_month_name_(eg_JAN): "Nom du mois sur 3 lettres (ex. JAN)"
|
||||
day_in_the_month_(eg_1): "Jour dans le mois (ex. 1)"
|
||||
2_digits_day_in_the_month_(eg_01): "Jour dans le mois sur 2 chiffres (ex. 01)"
|
||||
(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day): "Nombre de facture dans le jour, sur (n) chiffres (ex. ddd => 002 : 2ème facture du jour)"
|
||||
(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month): "Nombre de facture dans le mois, sur (n) chiffres (ex. mmmm => 0012 : 12ème facture ce mois)"
|
||||
(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year): "Nombre de facture dans l'année, sur (n) chiffres (ex. yyyyyy => 000008 : 8ème facture cette année)"
|
||||
beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Attention : si le nombre dépasse la longueur demandée, il sera tronqué par la gauche."
|
||||
(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order): "Nombre de commandes, sur (n) chiffres (ex. nnnn => 0327 : 327ème commande)"
|
||||
(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day): "Nombre de commandes dans le jour, sur (n) chiffres (ex. ddd => 002 : 2ème commande du jour)"
|
||||
(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month): "Nombre de commandes dans le mois, sur (n) chiffres (ex. mmmm => 0012 : 12ème commande ce mois)"
|
||||
(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year): "Nombre de commandes dans l'année, sur (n) chiffres (ex. yyyyyy => 000008 : 8ème commande cette année)"
|
||||
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Ajoute une information relative à la vente en ligne, uniquement si cela concerne la facture."
|
||||
this_will_never_be_added_when_a_refund_notice_is_present: "Ceci ne sera jamais cumulé avec une information de remboursement."
|
||||
(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe): '(ex. X[/VL] ajoutera "/VL" aux factures réglées avec stripe)'
|
||||
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Ajoute une information relative aux remboursements, uniquement si cela concerne la facture. "
|
||||
this_will_never_be_added_when_an_online_sales_notice_is_present: "Ceci ne sera jamais cumulé avec une information de vente en ligne."
|
||||
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ex. R[/A] ajoutera "/A" aux factures de remboursement)'
|
||||
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Ajoute une information relative au paiement par le porte-monnaie, uniquement si cela concerne la facture."
|
||||
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(ex. W[/PM] ajoutera "/PM" aux factures réglées avec porte-monnaie)'
|
||||
code: "Code"
|
||||
enable_the_code: "Activer le code"
|
||||
enabled: "Activé"
|
||||
disabled: "Désactivé"
|
||||
order_number: "Numéro de Commande"
|
||||
elements: "Éléments"
|
||||
VAT: "TVA"
|
||||
enable_VAT: "Activer la TVA"
|
||||
VAT_rate: "Taux de TVA"
|
||||
refund_invoice_successfully_created: "La facture d'avoir a bien été créée."
|
||||
create_a_refund_on_this_invoice: "Générer un avoir sur cette facture"
|
||||
creation_date_for_the_refund: "Date d'émission de l'avoir"
|
||||
creation_date_is_required: "La date d'émission est requise."
|
||||
refund_mode: "Mode de remboursement :"
|
||||
do_you_want_to_disable_the_user_s_subscription: "Souhaitez-vous désactiver l'abonnement de l'utilisateur :"
|
||||
elements_to_refund: "Éléments à rembourser"
|
||||
description_(optional): "Description (optionnelle) :"
|
||||
will_appear_on_the_refund_invoice: "Apparaîtra sur la facture de remboursement."
|
||||
none: "Aucun" # grammar note: concordance with "payment mean"
|
||||
by_cash: "En espèces"
|
||||
by_cheque: "Par chèque"
|
||||
by_transfer: "Par virement"
|
||||
by_wallet: "Par porte-monnaie"
|
||||
you_must_select_at_least_one_element_to_create_a_refund: "Vous devez sélectionner au moins un élément sur lequel créer un avoir."
|
||||
unable_to_create_the_refund: "Impossible de créer l'avoir"
|
||||
invoice_reference_successfully_saved: "La référence facture a bien été enregistrée."
|
||||
an_error_occurred_while_saving_invoice_reference: "Une erreur est survenue lors de l'enregistrement de la référence facture."
|
||||
invoicing_code_succesfully_saved: "Le code de facturation a bien été enregistré."
|
||||
an_error_occurred_while_saving_the_invoicing_code: "Une erreur est survenue lors de l'enregistrement du code de facturation."
|
||||
code_successfully_activated: "Le code a bien été activé."
|
||||
code_successfully_disabled: "Le code a bien été désactivé."
|
||||
an_error_occurred_while_activating_the_invoicing_code: "Une erreur est survenue lors de l'activation du code de facturation."
|
||||
order_number_successfully_saved: "Le numéro de commande a bien été enregistré."
|
||||
an_error_occurred_while_saving_the_order_number: "Une erreur est survenue lors de l'enregistrement du numéro de commande."
|
||||
VAT_rate_successfully_saved: "Le taux de TVA a bien été enregistré."
|
||||
an_error_occurred_while_saving_the_VAT_rate: "Une erreur est survenue lors de l'enregistrement du taux de TVA."
|
||||
VAT_successfully_activated: "La TVA a bien été activé."
|
||||
VAT_successfully_disabled: "La TVA a bien été désactivé."
|
||||
an_error_occurred_while_activating_the_VAT: "Une erreur est survenue lors de l'activation de la TVA."
|
||||
text_successfully_saved: "Le texte a bien été enregistré."
|
||||
an_error_occurred_while_saving_the_text: "Une erreur est survenue lors de l'enregistrement du texte."
|
||||
address_and_legal_information_successfully_saved: "L'adresse et les informations légales ont bien été enregistrées."
|
||||
an_error_occurred_while_saving_the_address_and_the_legal_information: "Une erreur est survenue lors de l'enregistrement de l'adresse et des informations légales."
|
||||
logo_successfully_saved: "Le logo bien été enregistré."
|
||||
an_error_occurred_while_saving_the_logo: "Une erreur est survenue lors de l'enregistrement du logo."
|
||||
invoices:
|
||||
# liste de toutes les factures & paramètres de facturation
|
||||
invoices: "Factures"
|
||||
invoices_list: "Liste des factures"
|
||||
filter_invoices: "Filtrer les factures"
|
||||
invoice_#_: "Facture n° :"
|
||||
customer_: "Client :"
|
||||
date_: "Date :"
|
||||
invoice_#: "Facture n°"
|
||||
date: "Date"
|
||||
price: "Prix"
|
||||
customer: "Client"
|
||||
download_the_invoice: "Télécharger la facture"
|
||||
download_the_credit_note: "Télécharger l'avoir"
|
||||
credit_note: "Avoir"
|
||||
display_more_invoices: "Afficher plus de factures ..."
|
||||
no_invoices_for_now: "Aucune facture pour le moment."
|
||||
invoicing_settings: "Paramètres de facturation"
|
||||
change_logo: "Changer le logo"
|
||||
john_smith: "Jean Dupont"
|
||||
john_smith@example_com: "jean.dupont@example.com"
|
||||
invoice_reference_: "Référence facture :"
|
||||
code_: "Code :"
|
||||
code_disabled: "Code désactivé"
|
||||
order_#: "N° Commande :"
|
||||
invoice_issued_on_DATE_at_TIME: "Facture éditée le {{DATE}} à {{TIME}}" # angular interpolation
|
||||
object_reservation_of_john_smith_on_DATE_at_TIME: "Objet : Réservation de Jean Dupont le {{DATE}} à {{TIME}}" # angular interpolation
|
||||
order_summary: "Récapitulatif de la commande :"
|
||||
details: "Détails"
|
||||
amount: "Montant"
|
||||
machine_booking-3D_printer: "Réservation Machine - Imprimante 3D"
|
||||
total_amount: "Montant total"
|
||||
total_including_all_taxes: "Total TTC"
|
||||
VAT_disabled: "TVA désactivée"
|
||||
including_VAT: "Dont TVA"
|
||||
including_total_excluding_taxes: "Dont total HT"
|
||||
including_amount_payed_on_ordering: "Dont montant payé à la commande"
|
||||
settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Règlement effectué par carte bancaire le {{DATE}} à {{TIME}}, pour un montant de {{AMOUNT}}"
|
||||
important_notes: "Informations importantes"
|
||||
address_and_legal_information: "Adresse et informations légales"
|
||||
invoice_reference: "Référence facture"
|
||||
year: "Année"
|
||||
month: "Mois"
|
||||
day: "Jour"
|
||||
"#_of_invoice": "N° de facture"
|
||||
online_sales: "Vente en ligne"
|
||||
wallet: "Porte-monnaie"
|
||||
refund: "Remboursement"
|
||||
model: "Modèle"
|
||||
documentation: "Documentation"
|
||||
2_digits_year_(eg_70): "Année sur 2 chiffres (ex. 70)"
|
||||
4_digits_year_(eg_1970): "Année sur 4 chiffres (ex. 1970)"
|
||||
month_number_(eg_1): "Numéro du mois (ex. 1)"
|
||||
2_digits_month_number_(eg_01): "Numéro du mois sur 2 chiffres (ex. 01)"
|
||||
3_characters_month_name_(eg_JAN): "Nom du mois sur 3 lettres (ex. JAN)"
|
||||
day_in_the_month_(eg_1): "Jour dans le mois (ex. 1)"
|
||||
2_digits_day_in_the_month_(eg_01): "Jour dans le mois sur 2 chiffres (ex. 01)"
|
||||
(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day): "Nombre de facture dans le jour, sur (n) chiffres (ex. ddd => 002 : 2ème facture du jour)"
|
||||
(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month): "Nombre de facture dans le mois, sur (n) chiffres (ex. mmmm => 0012 : 12ème facture ce mois)"
|
||||
(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year): "Nombre de facture dans l'année, sur (n) chiffres (ex. yyyyyy => 000008 : 8ème facture cette année)"
|
||||
beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Attention : si le nombre dépasse la longueur demandée, il sera tronqué par la gauche."
|
||||
(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order): "Nombre de commandes, sur (n) chiffres (ex. nnnn => 0327 : 327ème commande)"
|
||||
(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day): "Nombre de commandes dans le jour, sur (n) chiffres (ex. ddd => 002 : 2ème commande du jour)"
|
||||
(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month): "Nombre de commandes dans le mois, sur (n) chiffres (ex. mmmm => 0012 : 12ème commande ce mois)"
|
||||
(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year): "Nombre de commandes dans l'année, sur (n) chiffres (ex. yyyyyy => 000008 : 8ème commande cette année)"
|
||||
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Ajoute une information relative à la vente en ligne, uniquement si cela concerne la facture."
|
||||
this_will_never_be_added_when_a_refund_notice_is_present: "Ceci ne sera jamais cumulé avec une information de remboursement."
|
||||
(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe): '(ex. X[/VL] ajoutera "/VL" aux factures réglées avec stripe)'
|
||||
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Ajoute une information relative aux remboursements, uniquement si cela concerne la facture. "
|
||||
this_will_never_be_added_when_an_online_sales_notice_is_present: "Ceci ne sera jamais cumulé avec une information de vente en ligne."
|
||||
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ex. R[/A] ajoutera "/A" aux factures de remboursement)'
|
||||
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Ajoute une information relative au paiement par le porte-monnaie, uniquement si cela concerne la facture."
|
||||
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(ex. W[/PM] ajoutera "/PM" aux factures réglées avec porte-monnaie)'
|
||||
code: "Code"
|
||||
enable_the_code: "Activer le code"
|
||||
enabled: "Activé"
|
||||
disabled: "Désactivé"
|
||||
order_number: "Numéro de Commande"
|
||||
elements: "Éléments"
|
||||
VAT: "TVA"
|
||||
enable_VAT: "Activer la TVA"
|
||||
VAT_rate: "Taux de TVA"
|
||||
refund_invoice_successfully_created: "La facture d'avoir a bien été créée."
|
||||
create_a_refund_on_this_invoice: "Générer un avoir sur cette facture"
|
||||
creation_date_for_the_refund: "Date d'émission de l'avoir"
|
||||
creation_date_is_required: "La date d'émission est requise."
|
||||
refund_mode: "Mode de remboursement :"
|
||||
do_you_want_to_disable_the_user_s_subscription: "Souhaitez-vous désactiver l'abonnement de l'utilisateur :"
|
||||
elements_to_refund: "Éléments à rembourser"
|
||||
description: "Description"
|
||||
description_(optional): "Description (optionnelle) :"
|
||||
will_appear_on_the_refund_invoice: "Apparaîtra sur la facture de remboursement."
|
||||
none: "Aucun" # grammar note: concordance with "payment mean"
|
||||
by_cash: "En espèces"
|
||||
by_cheque: "Par chèque"
|
||||
by_transfer: "Par virement"
|
||||
by_wallet: "Par porte-monnaie"
|
||||
you_must_select_at_least_one_element_to_create_a_refund: "Vous devez sélectionner au moins un élément sur lequel créer un avoir."
|
||||
unable_to_create_the_refund: "Impossible de créer l'avoir"
|
||||
invoice_reference_successfully_saved: "La référence facture a bien été enregistrée."
|
||||
an_error_occurred_while_saving_invoice_reference: "Une erreur est survenue lors de l'enregistrement de la référence facture."
|
||||
invoicing_code_succesfully_saved: "Le code de facturation a bien été enregistré."
|
||||
an_error_occurred_while_saving_the_invoicing_code: "Une erreur est survenue lors de l'enregistrement du code de facturation."
|
||||
code_successfully_activated: "Le code a bien été activé."
|
||||
code_successfully_disabled: "Le code a bien été désactivé."
|
||||
an_error_occurred_while_activating_the_invoicing_code: "Une erreur est survenue lors de l'activation du code de facturation."
|
||||
order_number_successfully_saved: "Le numéro de commande a bien été enregistré."
|
||||
an_error_occurred_while_saving_the_order_number: "Une erreur est survenue lors de l'enregistrement du numéro de commande."
|
||||
VAT_rate_successfully_saved: "Le taux de TVA a bien été enregistré."
|
||||
an_error_occurred_while_saving_the_VAT_rate: "Une erreur est survenue lors de l'enregistrement du taux de TVA."
|
||||
VAT_successfully_activated: "La TVA a bien été activé."
|
||||
VAT_successfully_disabled: "La TVA a bien été désactivé."
|
||||
an_error_occurred_while_activating_the_VAT: "Une erreur est survenue lors de l'activation de la TVA."
|
||||
text_successfully_saved: "Le texte a bien été enregistré."
|
||||
an_error_occurred_while_saving_the_text: "Une erreur est survenue lors de l'enregistrement du texte."
|
||||
address_and_legal_information_successfully_saved: "L'adresse et les informations légales ont bien été enregistrées."
|
||||
an_error_occurred_while_saving_the_address_and_the_legal_information: "Une erreur est survenue lors de l'enregistrement de l'adresse et des informations légales."
|
||||
logo_successfully_saved: "Le logo bien été enregistré."
|
||||
an_error_occurred_while_saving_the_logo: "Une erreur est survenue lors de l'enregistrement du logo."
|
||||
online_payment: "Paiement en ligne"
|
||||
close_accounting_period: "Clôturer une période comptable"
|
||||
close_from_date: "Clôturer depuis"
|
||||
start_date_is_required: "La date de début est requise"
|
||||
close_until_date: "Clôturer jusqu'au"
|
||||
end_date_is_required: "La date de fin est requise"
|
||||
previous_closings: "Fermetures précédentes"
|
||||
start_date: "Du"
|
||||
end_date: "Au"
|
||||
closed_at: "Clôturé le"
|
||||
closed_by: "Par"
|
||||
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."
|
||||
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"
|
||||
|
||||
members:
|
||||
# gestion des utilisateurs, des groupes, des étiquettes, etc.
|
||||
|
@ -113,8 +113,8 @@ pt:
|
||||
events_to_come: "Eventos futuros"
|
||||
events_to_come_asc: "Eventos futuros | ordem cronológica"
|
||||
on_DATE: "No {{DATE}}" # angular interpolation
|
||||
from_DATE: "Em {{DATE}}" # angular interpolation
|
||||
from_TIME: "Ás {{TIME}}" # angular interpolation
|
||||
from_DATE: "Em {{DATE}}" # angular interpolation
|
||||
from_TIME: "Ás {{TIME}}" # angular interpolation
|
||||
booking: "Reserva"
|
||||
sold_out: "Esgotado"
|
||||
cancelled: "Cancelado"
|
||||
@ -282,115 +282,141 @@ pt:
|
||||
subscription_successfully_changed: "Assinatura alterada com sucesso."
|
||||
|
||||
invoices:
|
||||
# list of all invoices & invoicing parameters
|
||||
invoices: "Faturas"
|
||||
invoices_list: "Lista de faturas"
|
||||
filter_invoices: "Filtrar faturas"
|
||||
invoice_#_: "Fatura #:"
|
||||
customer_: "Cliente:"
|
||||
date_: "Data:"
|
||||
invoice_#: "Fatura #"
|
||||
customer: "Cliente"
|
||||
credit_note: "Nota de crédito"
|
||||
display_more_invoices: "Mostrar mais faturas..."
|
||||
invoicing_settings: "Configurações do faturamento"
|
||||
change_logo: "Mudar o logo"
|
||||
john_smith: "John Smith"
|
||||
john_smith@example_com: "jean.smith@example.com"
|
||||
invoice_reference_: "Referencia de fatura:"
|
||||
code_: "Código:"
|
||||
code_disabled: "Código desabilitado"
|
||||
order_#: "Ordem #:"
|
||||
invoice_issued_on_DATE_at_TIME: "Fatura emitida em {{DATE}} ás {{TIME}}" # angular interpolation
|
||||
object_reservation_of_john_smith_on_DATE_at_TIME: "Objeto: Reserva do John Smith em {{DATE}} ás {{TIME}}" # angular interpolation
|
||||
order_summary: "Sumário de ordem:"
|
||||
details: "Detalhes"
|
||||
amount: "Montante"
|
||||
machine_booking-3D_printer: "Reserva de máquina - 3D printer"
|
||||
total_amount: "Montante total"
|
||||
total_including_all_taxes: "Total incluindo todas as taxas"
|
||||
VAT_disabled: "VAT desativado"
|
||||
including_VAT: "Incluindo VAT"
|
||||
including_total_excluding_taxes: "Incluindo o total de taxas excluidas"
|
||||
including_amount_payed_on_ordering: "Incluindo o valor pago na compra"
|
||||
settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Pagamento por cartão de débito em {{DATE}} ás {{TIME}}, no valor de {{AMOUNT}}"
|
||||
important_notes: "Notas importantes"
|
||||
address_and_legal_information: "Endereço e informações legais"
|
||||
invoice_reference: "Referencia de fatura"
|
||||
day: "Dia"
|
||||
"#_of_invoice": "# da fatura"
|
||||
online_sales: "Vendas online"
|
||||
wallet: "Carteira"
|
||||
refund: "Restituição"
|
||||
documentation: "Documentação"
|
||||
2_digits_year_(eg_70): "2 dígitos ano (ex 70)"
|
||||
4_digits_year_(eg_1970): "4 dígitos ano (ex. 1970)"
|
||||
month_number_(eg_1): "Número do mês (eg. 1)"
|
||||
2_digits_month_number_(eg_01): "2 digits month number (eg. 01)"
|
||||
3_characters_month_name_(eg_JAN): "3 characters month name (eg. JAN)"
|
||||
day_in_the_month_(eg_1): "Day in the month (eg. 1)"
|
||||
2_digits_day_in_the_month_(eg_01): "2 digits in the month (eg. 01)"
|
||||
(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day): "(n) digits, daily count of invoices (eg. ddd => 002 : 2nd invoice of the day)"
|
||||
(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month): "(n) digits, monthly count of invoices (eg. mmmm => 0012 : 12th invoice of the month)"
|
||||
(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year): "(n) digits, annual count of invoices (ex. yyyyyy => 000008 : 8th invoice of this year)"
|
||||
beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Beware: if the number exceed the specified length, it will be truncated by the left."
|
||||
(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order): "(n) digits, count of invoices (eg. nnnn => 0327 : 327th order)"
|
||||
(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day): "(n) digits, daily count of orders (eg. ddd => 002 : 2nd order of the day)"
|
||||
(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month): "(n) digits, monthly count of orders (eg. mmmm => 0012 : 12th order of the month)"
|
||||
(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year): "(n) digits, annual count of orders (ex. yyyyyy => 000008 : 8th order of this year)"
|
||||
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Add a notice regarding the online sales, only if the invoice is concerned."
|
||||
this_will_never_be_added_when_a_refund_notice_is_present: "This will never be added when a refund notice is present."
|
||||
(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe): '(eg. X[/VL] will add "/VL" to the invoices settled with stripe)'
|
||||
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Add a notice regarding refunds, only if the invoice is concerned."
|
||||
this_will_never_be_added_when_an_online_sales_notice_is_present: "This will never be added when an online sales notice is present."
|
||||
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ed. R[/A] will add "/A" to the refund invoices)'
|
||||
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Add a notice regarding the wallet, only if the invoice is concerned."
|
||||
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(eg. W[/PM] will add "/PM" to the invoices settled with wallet)'
|
||||
code: "Código"
|
||||
enable_the_code: "Ativar código"
|
||||
enabled: "Ativar"
|
||||
disabled: "Desativar"
|
||||
order_number: "Número de ordem"
|
||||
elements: "Elementos"
|
||||
VAT: "VAT"
|
||||
enable_VAT: "Ativar VAT"
|
||||
VAT_rate: "VAT taxa"
|
||||
refund_invoice_successfully_created: "Restituição de fatura criada com sucesso."
|
||||
create_a_refund_on_this_invoice: "Criar restituição de fatura"
|
||||
creation_date_for_the_refund: "Criação de data de restituição"
|
||||
creation_date_is_required: "Data de criação é obrigatório."
|
||||
refund_mode: "Modo de restituição:"
|
||||
do_you_want_to_disable_the_user_s_subscription: "Você deseja desativar a inscrição de usuários:"
|
||||
elements_to_refund: "Elementos para restituição"
|
||||
description_(optional): "Descrição (optional):"
|
||||
will_appear_on_the_refund_invoice: "Aparecerá na fatura de reembolso."
|
||||
none: "Vazio" # grammar note: concordance with "payment mean"
|
||||
by_cash: "Em dinheiro"
|
||||
by_cheque: "Em cheque"
|
||||
by_transfer: "Por transferência"
|
||||
by_wallet: "Pela carteira"
|
||||
you_must_select_at_least_one_element_to_create_a_refund: "Você deve selecionar pelo menos um elemento, para criar um reembolso."
|
||||
unable_to_create_the_refund: "Não foi possível criar reembolso"
|
||||
invoice_reference_successfully_saved: "Referência de fatura salva com sucesso."
|
||||
an_error_occurred_while_saving_invoice_reference: "Um erro ocorreu enquanto era salvo a fatura de referência."
|
||||
invoicing_code_succesfully_saved: "Invoicing code successfully saved."
|
||||
an_error_occurred_while_saving_the_invoicing_code: "An error occurred while saving the invoicing code."
|
||||
code_successfully_activated: "Código ativado com sucesso."
|
||||
code_successfully_disabled: "Código desativado com êxito."
|
||||
an_error_occurred_while_activating_the_invoicing_code: "Ocorreu um erro ao ativar o código de faturamento."
|
||||
order_number_successfully_saved: "Número de ordem salvo com sucesso."
|
||||
an_error_occurred_while_saving_the_order_number: "Ocorreu um erro ao salvar o número da ordem."
|
||||
VAT_rate_successfully_saved: "Taxa VAT salva com sucesso."
|
||||
an_error_occurred_while_saving_the_VAT_rate: "Um erro ocorreu ao salvar a taxa VAT."
|
||||
VAT_successfully_activated: "VAT ativado com sucesso."
|
||||
VAT_successfully_disabled: "VAT desativada com sucesso."
|
||||
an_error_occurred_while_activating_the_VAT: "Um erro ocorreu ao ativar VAT."
|
||||
text_successfully_saved: "Texto salvo com sucesso."
|
||||
an_error_occurred_while_saving_the_text: "Um erro ocorreu ao salvar texto."
|
||||
address_and_legal_information_successfully_saved: "Endereço e informações legais salvos com sucesso."
|
||||
an_error_occurred_while_saving_the_address_and_the_legal_information: "Um erro ocorreu ao salvar o endereço e informações legais."
|
||||
logo_successfully_saved: "Logo salvo com sucesso."
|
||||
an_error_occurred_while_saving_the_logo: "Um erro ocorreu ao salvar o logo."
|
||||
invoices:
|
||||
# list of all invoices & invoicing parameters
|
||||
invoices: "Faturas"
|
||||
invoices_list: "Lista de faturas"
|
||||
filter_invoices: "Filtrar faturas"
|
||||
invoice_#_: "Fatura #:"
|
||||
customer_: "Cliente:"
|
||||
date_: "Data:"
|
||||
invoice_#: "Fatura #"
|
||||
date: "Data"
|
||||
price: "Preço"
|
||||
customer: "Cliente"
|
||||
download_the_invoice: "Baixar a fatura"
|
||||
download_the_credit_note: "Baixar a nota de crédito"
|
||||
credit_note: "Nota de crédito"
|
||||
display_more_invoices: "Mostrar mais faturas..."
|
||||
no_invoices_for_now: "Nenhuma fatura."
|
||||
invoicing_settings: "Configurações do faturamento"
|
||||
change_logo: "Mudar o logo"
|
||||
john_smith: "John Smith"
|
||||
john_smith@example_com: "jean.smith@example.com"
|
||||
invoice_reference_: "Referencia de fatura:"
|
||||
code_: "Código:"
|
||||
code_disabled: "Código desabilitado"
|
||||
order_#: "Ordem #:"
|
||||
invoice_issued_on_DATE_at_TIME: "Fatura emitida em {{DATE}} ás {{TIME}}" # angular interpolation
|
||||
object_reservation_of_john_smith_on_DATE_at_TIME: "Objeto: Reserva do John Smith em {{DATE}} ás {{TIME}}" # angular interpolation
|
||||
order_summary: "Sumário de ordem:"
|
||||
details: "Detalhes"
|
||||
amount: "Montante"
|
||||
machine_booking-3D_printer: "Reserva de máquina - 3D printer"
|
||||
total_amount: "Montante total"
|
||||
total_including_all_taxes: "Total incluindo todas as taxas"
|
||||
VAT_disabled: "VAT desativado"
|
||||
including_VAT: "Incluindo VAT"
|
||||
including_total_excluding_taxes: "Incluindo o total de taxas excluidas"
|
||||
including_amount_payed_on_ordering: "Incluindo o valor pago na compra"
|
||||
settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Pagamento por cartão de débito em {{DATE}} ás {{TIME}}, no valor de {{AMOUNT}}"
|
||||
important_notes: "Notas importantes"
|
||||
address_and_legal_information: "Endereço e informações legais"
|
||||
invoice_reference: "Referencia de fatura"
|
||||
year: "Ano"
|
||||
month: "Mês"
|
||||
day: "Dia"
|
||||
"#_of_invoice": "# da fatura"
|
||||
online_sales: "Vendas online"
|
||||
wallet: "Carteira"
|
||||
refund: "Restituição"
|
||||
model: "Modelo"
|
||||
documentation: "Documentação"
|
||||
2_digits_year_(eg_70): "2 dígitos ano (ex 70)"
|
||||
4_digits_year_(eg_1970): "4 dígitos ano (ex. 1970)"
|
||||
month_number_(eg_1): "Número do mês (eg. 1)"
|
||||
2_digits_month_number_(eg_01): "2 digits month number (eg. 01)"
|
||||
3_characters_month_name_(eg_JAN): "3 characters month name (eg. JAN)"
|
||||
day_in_the_month_(eg_1): "Day in the month (eg. 1)"
|
||||
2_digits_day_in_the_month_(eg_01): "2 digits in the month (eg. 01)"
|
||||
(n)_digits_daily_count_of_invoices_(eg_ddd_002_2nd_invoice_of_the_day): "(n) digits, daily count of invoices (eg. ddd => 002 : 2nd invoice of the day)"
|
||||
(n)_digits_monthly_count_of_invoices_(eg_mmmm_0012_12th_invoice_of_this_month): "(n) digits, monthly count of invoices (eg. mmmm => 0012 : 12th invoice of the month)"
|
||||
(n)_digits_annual_amount_of_invoices_(eg_yyyyyy_000008_8th_invoice_of_this_year): "(n) digits, annual count of invoices (ex. yyyyyy => 000008 : 8th invoice of this year)"
|
||||
beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Beware: if the number exceed the specified length, it will be truncated by the left."
|
||||
(n)_digits_count_of_orders_(eg_nnnn_0327_327th_order): "(n) digits, count of invoices (eg. nnnn => 0327 : 327th order)"
|
||||
(n)_digits_daily_count_of_orders_(eg_ddd_002_2nd_order_of_the_day): "(n) digits, daily count of orders (eg. ddd => 002 : 2nd order of the day)"
|
||||
(n)_digits_monthly_count_of_orders_(eg_mmmm_0012_12th_order_of_this_month): "(n) digits, monthly count of orders (eg. mmmm => 0012 : 12th order of the month)"
|
||||
(n)_digits_annual_amount_of_orders_(eg_yyyyyy_000008_8th_order_of_this_year): "(n) digits, annual count of orders (ex. yyyyyy => 000008 : 8th order of this year)"
|
||||
add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Add a notice regarding the online sales, only if the invoice is concerned."
|
||||
this_will_never_be_added_when_a_refund_notice_is_present: "This will never be added when a refund notice is present."
|
||||
(eg_X[/VL]_will_add_/VL_to_the_invoices_settled_with_stripe): '(eg. X[/VL] will add "/VL" to the invoices settled with stripe)'
|
||||
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Add a notice regarding refunds, only if the invoice is concerned."
|
||||
this_will_never_be_added_when_an_online_sales_notice_is_present: "This will never be added when an online sales notice is present."
|
||||
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ed. R[/A] will add "/A" to the refund invoices)'
|
||||
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Add a notice regarding the wallet, only if the invoice is concerned."
|
||||
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(eg. W[/PM] will add "/PM" to the invoices settled with wallet)'
|
||||
code: "Código"
|
||||
enable_the_code: "Ativar código"
|
||||
enabled: "Ativar"
|
||||
disabled: "Desativar"
|
||||
order_number: "Número de ordem"
|
||||
elements: "Elementos"
|
||||
VAT: "VAT"
|
||||
enable_VAT: "Ativar VAT"
|
||||
VAT_rate: "VAT taxa"
|
||||
refund_invoice_successfully_created: "Restituição de fatura criada com sucesso."
|
||||
create_a_refund_on_this_invoice: "Criar restituição de fatura"
|
||||
creation_date_for_the_refund: "Criação de data de restituição"
|
||||
creation_date_is_required: "Data de criação é obrigatório."
|
||||
refund_mode: "Modo de restituição:"
|
||||
do_you_want_to_disable_the_user_s_subscription: "Você deseja desativar a inscrição de usuários:"
|
||||
elements_to_refund: "Elementos para restituição"
|
||||
description: "Descrição"
|
||||
description_(optional): "Descrição (optional):"
|
||||
will_appear_on_the_refund_invoice: "Aparecerá na fatura de reembolso."
|
||||
none: "Vazio" # grammar note: concordance with "payment mean"
|
||||
by_cash: "Em dinheiro"
|
||||
by_cheque: "Em cheque"
|
||||
by_transfer: "Por transferência"
|
||||
by_wallet: "Pela carteira"
|
||||
you_must_select_at_least_one_element_to_create_a_refund: "Você deve selecionar pelo menos um elemento, para criar um reembolso."
|
||||
unable_to_create_the_refund: "Não foi possível criar reembolso"
|
||||
invoice_reference_successfully_saved: "Referência de fatura salva com sucesso."
|
||||
an_error_occurred_while_saving_invoice_reference: "Um erro ocorreu enquanto era salvo a fatura de referência."
|
||||
invoicing_code_succesfully_saved: "Invoicing code successfully saved."
|
||||
an_error_occurred_while_saving_the_invoicing_code: "An error occurred while saving the invoicing code."
|
||||
code_successfully_activated: "Código ativado com sucesso."
|
||||
code_successfully_disabled: "Código desativado com êxito."
|
||||
an_error_occurred_while_activating_the_invoicing_code: "Ocorreu um erro ao ativar o código de faturamento."
|
||||
order_number_successfully_saved: "Número de ordem salvo com sucesso."
|
||||
an_error_occurred_while_saving_the_order_number: "Ocorreu um erro ao salvar o número da ordem."
|
||||
VAT_rate_successfully_saved: "Taxa VAT salva com sucesso."
|
||||
an_error_occurred_while_saving_the_VAT_rate: "Um erro ocorreu ao salvar a taxa VAT."
|
||||
VAT_successfully_activated: "VAT ativado com sucesso."
|
||||
VAT_successfully_disabled: "VAT desativada com sucesso."
|
||||
an_error_occurred_while_activating_the_VAT: "Um erro ocorreu ao ativar VAT."
|
||||
text_successfully_saved: "Texto salvo com sucesso."
|
||||
an_error_occurred_while_saving_the_text: "Um erro ocorreu ao salvar texto."
|
||||
address_and_legal_information_successfully_saved: "Endereço e informações legais salvos com sucesso."
|
||||
an_error_occurred_while_saving_the_address_and_the_legal_information: "Um erro ocorreu ao salvar o endereço e informações legais."
|
||||
logo_successfully_saved: "Logo salvo com sucesso."
|
||||
an_error_occurred_while_saving_the_logo: "Um erro ocorreu ao salvar o logo."
|
||||
online_payment: "Pagamento Online"
|
||||
close_accounting_period: "Close an accounting period" # translation_missing
|
||||
close_from_date: "Close from" # translation_missing
|
||||
start_date_is_required: "Start date is required" # translation_missing
|
||||
close_until_date: "Close until" # translation_missing
|
||||
end_date_is_required: "End date is required" # translation_missing
|
||||
previous_closings: "Previous closings" # translation_missing
|
||||
start_date: "From" # translation_missing
|
||||
end_date: "To" # translation_missing
|
||||
closed_at: "Closed at" # translation_missing
|
||||
closed_by: "By" # translation_missing
|
||||
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." # 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
|
||||
|
||||
members:
|
||||
# management of users, labels, groups, and so on
|
||||
@ -444,8 +470,8 @@ pt:
|
||||
an_error_occurred_when_saving_the_new_group: "Um erro ocorreu ao salvar novo grupo."
|
||||
group_successfully_deleted: "Grupo excluido com sucesso."
|
||||
unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it: "Não é possível excluir o grupo porque alguns usuários e / ou grupos ainda estão vinculados a ele."
|
||||
group_successfully_enabled_disabled: "Grupo {STATUS, select, true{desativado} other{ativado}} com sucesso."
|
||||
unable_to_enable_disable_group: "Não foi possível {STATUS, select, true{desativar} other{ativar}} grupo."
|
||||
group_successfully_enabled_disabled: "Grupo {STATUS, select, true{desativado} other{ativado}} com sucesso."
|
||||
unable_to_enable_disable_group: "Não foi possível {STATUS, select, true{desativar} other{ativar}} grupo."
|
||||
unable_to_disable_group_with_users: "Não é possível desabilitar grupo porque {USERS, plural, =1{existe} other{existem}} {USERS} {USERS, plural, =1{usuário} other{usuários}} {USERS, plural, =1{ativo} other{ativos}}."
|
||||
status_enabled: "Ativos"
|
||||
status_disabled: "Desabilitados"
|
||||
@ -563,7 +589,7 @@ pt:
|
||||
settings:
|
||||
# global application parameters and customization
|
||||
settings:
|
||||
tittle: "Title"
|
||||
tittle: "Title"
|
||||
customize_the_application: "Customizar a aplicação"
|
||||
general: "Geral"
|
||||
fablab_title: "Título do FabLab"
|
||||
@ -687,7 +713,7 @@ pt:
|
||||
client_successfully_updated: "Cliente alterado com sucesso."
|
||||
client_successfully_deleted: "Cliente excluído com sucesso."
|
||||
access_successfully_revoked: "Acesso revogado com sucesso."
|
||||
|
||||
|
||||
space_new:
|
||||
# create a new space
|
||||
space_new:
|
||||
@ -700,4 +726,4 @@ pt:
|
||||
# modify an exiting space
|
||||
space_edit:
|
||||
edit_the_space_NAME: "Editar o espaço: {{NAME}}" # angular interpolation
|
||||
validate_the_changes: "Validar mudanças"
|
||||
validate_the_changes: "Validar mudanças"
|
||||
|
@ -36,6 +36,9 @@ en:
|
||||
cannot_be_blank_at_same_time: "cannot be blank when %{field} is blank too"
|
||||
cannot_be_in_the_past: "cannot be in the past"
|
||||
cannot_be_before_previous_value: "cannot be before the previous value"
|
||||
cannot_overlap: "can't overlap an existing accounting period"
|
||||
cannot_encompass: "can't encompass an existing accounting period"
|
||||
in_closed_period: "can't be within a closed accounting period"
|
||||
|
||||
activemodel:
|
||||
errors:
|
||||
|
@ -36,6 +36,9 @@ es:
|
||||
cannot_be_blank_at_same_time: "no puede estar vacío cuando %{field} también está vacío"
|
||||
cannot_be_in_the_past: "no puede estar en el pasado"
|
||||
cannot_be_before_previous_value: "No puede estar antes del valor anterior."
|
||||
cannot_overlap: "can't overlap an existing accounting period" # missing translation
|
||||
cannot_encompass: "can't encompass an existing accounting period" # missing translation
|
||||
in_closed_period: "can't be within a closed accounting period" # missing translation
|
||||
|
||||
activemodel:
|
||||
errors:
|
||||
|
@ -36,6 +36,9 @@ fr:
|
||||
cannot_be_blank_at_same_time: "ou %{field} doit être rempli(e)"
|
||||
cannot_be_in_the_past: "ne peut pas être dans le passé"
|
||||
cannot_be_before_previous_value: "ne peut pas être antérieur(e) à la valeur précédente"
|
||||
cannot_overlap: "ne peut pas chevaucher une période comptable existante"
|
||||
cannot_encompass: "ne peut pas englober une période comptable existante"
|
||||
in_closed_period: "ne peut pas être dans une période comptable fermée"
|
||||
|
||||
activemodel:
|
||||
errors:
|
||||
@ -360,4 +363,4 @@ fr:
|
||||
|
||||
group:
|
||||
# nom du groupe utilisateur pour les administrateurs
|
||||
admins: 'Administrateurs'
|
||||
admins: 'Administrateurs'
|
||||
|
@ -36,6 +36,9 @@ pt:
|
||||
cannot_be_blank_at_same_time: "Não pode ficar em branco quando %{field} estiver em branco também"
|
||||
cannot_be_in_the_past: "não pode ser no passado"
|
||||
cannot_be_before_previous_value: "não pode ser antes do valor anterior"
|
||||
cannot_overlap: "can't overlap an existing accounting period" # missing translation
|
||||
cannot_encompass: "can't encompass an existing accounting period" # missing translation
|
||||
in_closed_period: "can't be within a closed accounting period" # missing translation
|
||||
|
||||
activemodel:
|
||||
errors:
|
||||
|
@ -1,3 +1,4 @@
|
||||
dsb:
|
||||
date:
|
||||
abbr_day_names:
|
||||
- Nj
|
||||
@ -8,7 +9,7 @@
|
||||
- Pě
|
||||
- So
|
||||
abbr_month_names:
|
||||
-
|
||||
-
|
||||
- jan
|
||||
- feb
|
||||
- měr
|
||||
@ -34,7 +35,7 @@
|
||||
long: ! '%d. %B %Y'
|
||||
short: ! '%d %b'
|
||||
month_names:
|
||||
-
|
||||
-
|
||||
- Januar
|
||||
- Februar
|
||||
- Měrc
|
||||
|
@ -127,6 +127,9 @@ Rails.application.routes.draw do
|
||||
end
|
||||
resources :price_categories
|
||||
resources :spaces
|
||||
resources :accounting_periods do
|
||||
get 'last_closing_end', on: :collection
|
||||
end
|
||||
|
||||
# i18n
|
||||
# regex allows using dots in URL for 'state'
|
||||
|
15
db/migrate/20190107103632_create_accounting_periods.rb
Normal file
15
db/migrate/20190107103632_create_accounting_periods.rb
Normal file
@ -0,0 +1,15 @@
|
||||
class CreateAccountingPeriods < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :accounting_periods do |t|
|
||||
t.date :start_at
|
||||
t.date :end_at
|
||||
t.datetime :closed_at
|
||||
t.integer :closed_by
|
||||
|
||||
t.timestamps null: false
|
||||
end
|
||||
|
||||
add_foreign_key :accounting_periods, :users, column: :closed_by, primary_key: :id
|
||||
|
||||
end
|
||||
end
|
13
db/migrate/20190107111749_protect_accounting_periods.rb
Normal file
13
db/migrate/20190107111749_protect_accounting_periods.rb
Normal file
@ -0,0 +1,13 @@
|
||||
class ProtectAccountingPeriods < ActiveRecord::Migration
|
||||
|
||||
# PostgreSQL only
|
||||
def up
|
||||
execute("CREATE RULE accounting_periods_del_protect AS ON DELETE TO #{AccountingPeriod.arel_table.name} DO INSTEAD NOTHING;")
|
||||
execute("CREATE RULE accounting_periods_upd_protect AS ON UPDATE TO #{AccountingPeriod.arel_table.name} DO INSTEAD NOTHING;")
|
||||
end
|
||||
|
||||
def down
|
||||
execute("DROP RULE IF EXISTS accounting_periods_del_protect ON #{AccountingPeriod.arel_table.name};")
|
||||
execute("DROP RULE IF EXISTS accounting_periods_upd_protect ON #{AccountingPeriod.arel_table.name};")
|
||||
end
|
||||
end
|
12
db/schema.rb
12
db/schema.rb
@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20181217110454) do
|
||||
ActiveRecord::Schema.define(version: 20190107111749) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@ -31,6 +31,15 @@ ActiveRecord::Schema.define(version: 20181217110454) do
|
||||
|
||||
add_index "abuses", ["signaled_type", "signaled_id"], name: "index_abuses_on_signaled_type_and_signaled_id", using: :btree
|
||||
|
||||
create_table "accounting_periods", force: :cascade do |t|
|
||||
t.date "start_at"
|
||||
t.date "end_at"
|
||||
t.datetime "closed_at"
|
||||
t.integer "closed_by"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "addresses", force: :cascade do |t|
|
||||
t.string "address", limit: 255
|
||||
t.string "street_number", limit: 255
|
||||
@ -856,6 +865,7 @@ ActiveRecord::Schema.define(version: 20181217110454) do
|
||||
|
||||
add_index "wallets", ["user_id"], name: "index_wallets_on_user_id", using: :btree
|
||||
|
||||
add_foreign_key "accounting_periods", "users", column: "closed_by"
|
||||
add_foreign_key "availability_tags", "availabilities"
|
||||
add_foreign_key "availability_tags", "tags"
|
||||
add_foreign_key "event_price_categories", "events"
|
||||
|
@ -14,6 +14,7 @@ services:
|
||||
- ${PWD}/exports:/usr/src/app/exports
|
||||
- ${PWD}/log:/var/log/supervisor
|
||||
- ${PWD}/plugins:/usr/src/app/plugins
|
||||
- ${PWD}/accounting:/usr/src/app/accounting
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
|
5
test/fixtures/accounting_periods.yml
vendored
Normal file
5
test/fixtures/accounting_periods.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
period2015:
|
||||
start_at: 2015-01-01
|
||||
end_at: 2015-12-31
|
||||
closed_at: 2016-01-04 18:12:07
|
||||
closed_by: 1
|
12
test/fixtures/invoice_items.yml
vendored
12
test/fixtures/invoice_items.yml
vendored
@ -33,7 +33,6 @@ invoice_item_3:
|
||||
subscription_id: 3
|
||||
invoice_item_id:
|
||||
|
||||
|
||||
invoice_item_4:
|
||||
id: 4
|
||||
invoice_id: 4
|
||||
@ -45,3 +44,14 @@ invoice_item_4:
|
||||
subscription_id:
|
||||
invoice_item_id:
|
||||
|
||||
invoice_item_5:
|
||||
id: 5
|
||||
invoice_id: 5
|
||||
stp_invoice_item_id:
|
||||
amount: 1500
|
||||
created_at: 2015-06-10 11:20:01.341130000 Z
|
||||
updated_at: 2015-06-10 11:20:01.341130000 Z
|
||||
description: Imprimante 3D June 15, 2015 12:00 - 01:00 PM
|
||||
subscription_id:
|
||||
invoice_item_id:
|
||||
|
||||
|
19
test/fixtures/invoices.yml
vendored
19
test/fixtures/invoices.yml
vendored
@ -66,4 +66,21 @@ invoice_4:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
description:
|
||||
|
||||
invoice_5:
|
||||
id: 5
|
||||
invoiced_id: 2
|
||||
invoiced_type: Reservation
|
||||
stp_invoice_id:
|
||||
total: 1500
|
||||
created_at: 2015-06-10 11:20:01.341130000 Z
|
||||
updated_at: 2015-06-10 11:20:01.341130000 Z
|
||||
user_id: 3
|
||||
reference: '1506031'
|
||||
avoir_mode:
|
||||
avoir_date:
|
||||
invoice_id:
|
||||
type:
|
||||
subscription_to_expire:
|
||||
description:
|
||||
|
13
test/fixtures/reservations.yml
vendored
13
test/fixtures/reservations.yml
vendored
@ -8,4 +8,15 @@ reservation_1:
|
||||
reservable_id: 2
|
||||
reservable_type: Training
|
||||
stp_invoice_id:
|
||||
nb_reserve_places:
|
||||
nb_reserve_places:
|
||||
|
||||
reservation_2:
|
||||
id: 2
|
||||
user_id: 3
|
||||
message:
|
||||
created_at: 2015-06-10 11:20:01.341130000 Z
|
||||
updated_at: 2015-06-10 11:20:01.341130000 Z
|
||||
reservable_id: 4
|
||||
reservable_type: Machine
|
||||
stp_invoice_id:
|
||||
nb_reserve_places:
|
||||
|
14
test/fixtures/slots.yml
vendored
14
test/fixtures/slots.yml
vendored
@ -9,4 +9,16 @@ slot_1:
|
||||
ex_start_at:
|
||||
canceled_at:
|
||||
ex_end_at:
|
||||
offered:
|
||||
offered:
|
||||
|
||||
slot_2:
|
||||
id: 2
|
||||
start_at: 2015-06-15 12:00:28.000000000 Z
|
||||
end_at: 2015-06-15 13:00:28.000000000 Z
|
||||
created_at: 2015-06-10 11:20:01.341130000 Z
|
||||
updated_at: 2015-06-10 11:20:01.341130000 Z
|
||||
availability_id: 13
|
||||
ex_start_at:
|
||||
canceled_at:
|
||||
ex_end_at:
|
||||
offered:
|
||||
|
6
test/fixtures/slots_reservations.yml
vendored
6
test/fixtures/slots_reservations.yml
vendored
@ -2,4 +2,8 @@
|
||||
|
||||
one:
|
||||
slot_id: 1
|
||||
reservation_id: 1
|
||||
reservation_id: 1
|
||||
|
||||
two:
|
||||
slot_id: 2
|
||||
reservation_id: 2
|
||||
|
45
test/integration/accounting_period_test.rb
Normal file
45
test/integration/accounting_period_test.rb
Normal file
@ -0,0 +1,45 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AccountingPeriodTest < ActionDispatch::IntegrationTest
|
||||
|
||||
def setup
|
||||
@admin = User.find_by(username: 'admin')
|
||||
login_as(@admin, scope: :user)
|
||||
end
|
||||
|
||||
test 'admin closes an accounting period' do
|
||||
start_at = '2012-01-01T00:00:00.000Z'
|
||||
end_at = '2012-12-31T00: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 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the correct period was closed successfully
|
||||
period = json_response(response.body)
|
||||
accounting_period = AccountingPeriod.find(period[:id])
|
||||
assert_dates_equal start_at.to_date, period[:start_at]
|
||||
assert_dates_equal end_at.to_date, period[:end_at]
|
||||
|
||||
# Check archive file was created
|
||||
assert FileTest.exists? accounting_period.archive_file
|
||||
|
||||
# Check archive matches
|
||||
archive = File.read(accounting_period.archive_file)
|
||||
archive_json = JSON.parse(archive)
|
||||
invoices = Invoice.where(
|
||||
'created_at >= :start_date AND created_at <= :end_date',
|
||||
start_date: start_at.to_datetime, end_date: end_at.to_datetime
|
||||
)
|
||||
assert_equal invoices.count, archive_json.count
|
||||
end
|
||||
|
||||
end
|
86
test/integration/invoices/as_admin_test.rb
Normal file
86
test/integration/invoices/as_admin_test.rb
Normal file
@ -0,0 +1,86 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class InvoicesTest < ActionDispatch::IntegrationTest
|
||||
|
||||
# Called before every test method runs. Can be used
|
||||
# to set up fixture information.
|
||||
def setup
|
||||
@admin = User.find_by(username: 'admin')
|
||||
login_as(@admin, scope: :user)
|
||||
end
|
||||
|
||||
test 'admin list invoices' do
|
||||
post '/api/invoices/list', { query: {
|
||||
number: '',
|
||||
customer: '',
|
||||
date: nil,
|
||||
order_by: '-reference',
|
||||
page: 1,
|
||||
size: 20 # test db may have < 20 invoices
|
||||
} }.to_json, default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 200, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check that we have all invoices
|
||||
invoices = json_response(response.body)
|
||||
assert_equal Invoice.count, invoices.size, 'some invoices are missing'
|
||||
|
||||
# Check that invoices are ordered by reference
|
||||
assert_equal '1604002', invoices.first[:reference]
|
||||
assert_equal '1203001', invoices.last[:reference]
|
||||
end
|
||||
|
||||
test 'admin generates a refund' do
|
||||
date = DateTime.now.iso8601
|
||||
|
||||
post '/api/invoices', { avoir: {
|
||||
avoir_date: date,
|
||||
avoir_mode: 'cash',
|
||||
description: 'Lorem ipsum',
|
||||
invoice_id: 4,
|
||||
invoice_items_ids: [4],
|
||||
subscription_to_expire: false
|
||||
} }.to_json, default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check that the refund match
|
||||
refund = json_response(response.body)
|
||||
avoir = Avoir.find(refund[:id])
|
||||
|
||||
assert_dates_equal date, refund[:avoir_date]
|
||||
assert_dates_equal date, refund[:date]
|
||||
assert_equal 'cash', refund[:avoir_mode]
|
||||
assert_equal false, refund[:has_avoir]
|
||||
assert_equal 4, refund[:invoice_id]
|
||||
assert_equal 4, refund[:items][0][:invoice_item_id]
|
||||
assert_match %r{^[0-9]+/A$}, refund[:reference]
|
||||
assert_equal 'Lorem ipsum', avoir.description
|
||||
end
|
||||
|
||||
test 'admin fails generates a refund in closed period' do
|
||||
date = '2015-10-01T13:09:55+01:00'.to_datetime
|
||||
|
||||
post '/api/invoices', { avoir: {
|
||||
avoir_date: date,
|
||||
avoir_mode: 'cash',
|
||||
description: 'Unable to refund',
|
||||
invoice_id: 5,
|
||||
invoice_items_ids: [5],
|
||||
subscription_to_expire: false
|
||||
} }.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 was handled
|
||||
assert_match(/#{I18n.t('errors.messages.in_closed_period')}/, response.body)
|
||||
end
|
||||
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class MemebersTest < ActionDispatch::IntegrationTest
|
||||
class MembersTest < ActionDispatch::IntegrationTest
|
||||
|
||||
# Called before every test method runs. Can be used
|
||||
# to set up fixture information.
|
||||
|
Loading…
x
Reference in New Issue
Block a user