mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-30 11:24:21 +01:00
Merge branch 'dev' for release 2.8.2
This commit is contained in:
commit
c73f9424ae
2
.gitignore
vendored
2
.gitignore
vendored
@ -34,6 +34,8 @@
|
||||
# XLSX exports
|
||||
/exports/*
|
||||
|
||||
# Archives of cLosed accounting periods
|
||||
/accounting/*
|
||||
|
||||
.DS_Store
|
||||
|
||||
|
10
.rubocop.yml
10
.rubocop.yml
@ -1,5 +1,5 @@
|
||||
Metrics/LineLength:
|
||||
Max: 125
|
||||
Max: 130
|
||||
Metrics/MethodLength:
|
||||
Max: 30
|
||||
Metrics/CyclomaticComplexity:
|
||||
@ -7,10 +7,16 @@ Metrics/CyclomaticComplexity:
|
||||
Metrics/PerceivedComplexity:
|
||||
Max: 9
|
||||
Metrics/AbcSize:
|
||||
Max: 42
|
||||
Max: 45
|
||||
Metrics/ClassLength:
|
||||
Max: 200
|
||||
Style/BracesAroundHashParameters:
|
||||
EnforcedStyle: context_dependent
|
||||
Style/RegexpLiteral:
|
||||
EnforcedStyle: slashes
|
||||
Style/EmptyElse:
|
||||
EnforcedStyle: empty
|
||||
Style/ClassAndModuleChildren:
|
||||
EnforcedStyle: compact
|
||||
Style/AndOr:
|
||||
EnforcedStyle: conditionals
|
||||
|
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,5 +1,22 @@
|
||||
# Changelog Fab Manager
|
||||
|
||||
## v2.8.2 2019 January 22
|
||||
|
||||
- Removed ability to disable invoicing for an user
|
||||
- Fixed a missing translation in plan form
|
||||
- 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
|
||||
- Fix a bug: unable to delete an admin who has changed a setting
|
||||
- Fix a bug: unable to create/edit a plan of 12 months or 52 weeks
|
||||
- Fix a bug: Unable to search in user autocomplete fields
|
||||
- Fix a bug: Invalid translation in new partner modal
|
||||
- Improved user autocompletion when using multiple words
|
||||
- Refactored frontend invoices translations
|
||||
- Updated RailRoady 1.4.0 to 1.5.3
|
||||
- [TODO DEPLOY] `bundle install`
|
||||
|
||||
## v2.8.1 2019 January 02
|
||||
|
||||
- Fix ES upgrade: when docker-compose file is using ${PWD}, the ES config volume is attached to the wrong container
|
||||
|
@ -318,7 +318,7 @@ GEM
|
||||
rack
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
railroady (1.4.0)
|
||||
railroady (1.5.3)
|
||||
rails (4.2.11)
|
||||
actionmailer (= 4.2.11)
|
||||
actionpack (= 4.2.11)
|
||||
|
@ -160,10 +160,14 @@ This procedure is not easy to follow so if you don't need to write some code for
|
||||
- **Please note**: Your password length must be between 8 and 128 characters, otherwise db:seed will be rejected. This is configured in [config/initializers/devise.rb](config/initializers/devise.rb)
|
||||
|
||||
```bash
|
||||
# for dev
|
||||
rake db:create
|
||||
rake db:migrate
|
||||
ADMIN_EMAIL='youradminemail' ADMIN_PASSWORD='youradminpassword' rake db:seed
|
||||
rake fablab:es_build_stats
|
||||
# for tests
|
||||
RAILS_ENV=test rake db:create
|
||||
RAILS_ENV=test rake db:migrate
|
||||
```
|
||||
|
||||
14. Create the pids folder used by Sidekiq. If you want to use a different location, you can configure it in `config/sidekiq.yml`
|
||||
@ -252,6 +256,9 @@ environment.
|
||||
rake db:migrate
|
||||
ADMIN_EMAIL='youradminemail' ADMIN_PASSWORD='youradminpassword' rake db:seed
|
||||
rake fablab:es_build_stats
|
||||
# for tests
|
||||
RAILS_ENV=test rake db:create
|
||||
RAILS_ENV=test rake db:migrate
|
||||
```
|
||||
|
||||
11. Start the application and visit `localhost:3000` on your browser to check that it works:
|
||||
|
@ -105,7 +105,7 @@ 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',
|
||||
@ -119,7 +119,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 +193,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 +231,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 +277,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);
|
||||
});
|
||||
});
|
||||
@ -301,11 +301,15 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
},
|
||||
active () {
|
||||
return $scope.invoice.VAT.active;
|
||||
},
|
||||
history () {
|
||||
return Setting.get({ name: 'invoice_VAT-rate', history: true }).$promise;
|
||||
}
|
||||
},
|
||||
controller: ['$scope', '$uibModalInstance', 'rate', 'active', function ($scope, $uibModalInstance, rate, active) {
|
||||
controller: ['$scope', '$uibModalInstance', 'rate', 'active', 'history', function ($scope, $uibModalInstance, rate, active, history) {
|
||||
$scope.rate = rate;
|
||||
$scope.isSelected = active;
|
||||
$scope.history = history.setting.history;
|
||||
|
||||
$scope.ok = function () { $uibModalInstance.close({ rate: $scope.rate, active: $scope.isSelected }); };
|
||||
return $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
@ -316,24 +320,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 +350,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 +365,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);
|
||||
});
|
||||
};
|
||||
@ -418,9 +422,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);
|
||||
}
|
||||
);
|
||||
@ -498,7 +502,7 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
*/
|
||||
Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModalInstance', 'invoice', 'Invoice', 'growl', '_t',
|
||||
function ($scope, $uibModalInstance, invoice, Invoice, growl, _t) {
|
||||
/* PUBLIC SCOPE */
|
||||
/* PUBLIC SCOPE */
|
||||
|
||||
// invoice linked to the current refund
|
||||
$scope.invoice = invoice;
|
||||
@ -515,11 +519,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 +546,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 +561,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,13 +569,13 @@ 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'); };
|
||||
@ -592,7 +596,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' });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -142,7 +142,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
$scope.user.organization = orga;
|
||||
// display errors
|
||||
angular.forEach(error.data.errors, function (v, k) {
|
||||
angular.forEach(function (v, err) {
|
||||
angular.forEach(v, function (err) {
|
||||
$scope.alerts.push({
|
||||
msg: k + ': ' + err,
|
||||
type: 'danger'
|
||||
@ -175,9 +175,9 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
|
||||
return $scope.changePassword = function () {
|
||||
$scope.alerts = [];
|
||||
return $http.put('/users/password.json', { user: $scope.user }).success(function () { $uibModalInstance.close(); }).error(function (data) {
|
||||
angular.forEach(data.errors, function (v, k) {
|
||||
angular.forEach(function (v, err) {
|
||||
return $http.put('/users/password.json', { user: $scope.user }).then(function () { $uibModalInstance.close(); }).catch(function (data) {
|
||||
angular.forEach(data.data.errors, function (v, k) {
|
||||
angular.forEach(v, function (err) {
|
||||
$scope.alerts.push({
|
||||
msg: k + ': ' + err,
|
||||
type: 'danger'
|
||||
@ -400,7 +400,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
|
||||
$scope.user = { email: '' };
|
||||
return $scope.sendReset = function () {
|
||||
$scope.alerts = [];
|
||||
return $http.post('/users/password.json', { user: $scope.user }).success(function () { $uibModalInstance.close(); }).error(function () {
|
||||
return $http.post('/users/password.json', { user: $scope.user }).then(function () { $uibModalInstance.close(); }).catch(function () {
|
||||
$scope.alerts.push({
|
||||
msg: _t('your_email_address_is_unknown'),
|
||||
type: 'danger'
|
||||
|
@ -43,7 +43,7 @@ class MachinesController {
|
||||
if ((content.id == null)) {
|
||||
$scope.alerts = [];
|
||||
angular.forEach(content, function (v, k) {
|
||||
angular.forEach(function (v, err) {
|
||||
angular.forEach(v, function (err) {
|
||||
$scope.alerts.push({
|
||||
msg: k + ': ' + err,
|
||||
type: 'danger'
|
||||
|
@ -178,4 +178,9 @@
|
||||
border-radius: 5px;
|
||||
font-size: small;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-user-label {
|
||||
font-style: italic;
|
||||
color: #5a5a5a;
|
||||
}
|
||||
|
@ -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"
|
||||
@ -18,24 +18,24 @@
|
||||
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 +48,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 +57,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>
|
||||
|
@ -7,7 +7,7 @@
|
||||
</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>
|
||||
|
||||
@ -18,14 +18,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 +34,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 +43,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 +57,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 +78,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 }}
|
||||
<i class="fa fa-reply"></i> {{ 'invoices.credit_note' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
@ -92,9 +92,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 +103,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 +111,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 +199,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 +235,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 +327,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,28 +362,48 @@
|
||||
<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"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-t-lg">
|
||||
<h4 translate>{{ 'invoices.VAT_history' }}</h4>
|
||||
<table class="table">
|
||||
<head>
|
||||
<tr>
|
||||
<th translate>{{ 'invoices.VAT_rate' }}</th>
|
||||
<th translate>{{ 'invoices.changed_at' }}</th>
|
||||
<th translate>{{ 'invoices.changed_by' }}</th>
|
||||
</tr>
|
||||
</head>
|
||||
<tbody>
|
||||
<tr ng-repeat="value in history">
|
||||
<td>{{value.value}} %</td>
|
||||
<td>{{value.created_at | amDateFormat:'L LT'}}</td>
|
||||
<td>{{value.user.name}}<span class="no-user-label" ng-hide="value.user" translate>{{ 'invoices.deleted_user' }}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-warning" ng-click="ok()" translate>{{ 'confirm' }}</button>
|
||||
|
@ -11,26 +11,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="user[invoicing_disabled]" class="control-label col-sm-3" translate>
|
||||
{{ 'disable_invoices_generation' }}
|
||||
</label>
|
||||
<div class="col-sm-2">
|
||||
<input bs-switch
|
||||
ng-model="user.invoicing_disabled"
|
||||
name="user[invoicing_disabled]"
|
||||
type="checkbox"
|
||||
class="form-control"
|
||||
switch-on-text="{{ 'yes' | translate }}"
|
||||
switch-off-text="{{ 'no' | translate }}"
|
||||
switch-animate="true"/>
|
||||
<input type="hidden" name="user[invoicing_disabled]" value="{{user.invoicing_disabled}}">
|
||||
</div>
|
||||
<div class="col-sm-7">
|
||||
<span class="help-block"><i class="fa fa-warning"></i> {{ 'no_more_invoices_will_be_generated_for_' | translate }} <strong translate>{{ '_the_payments_carried_out_at_the_reception_' }}</strong> {{ '_regarding_this_user' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" translate>{{ 'trainings' }}</label>
|
||||
<div class="col-sm-10">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" translate>{{ 'new_partner' }}</h3>
|
||||
<h3 class="modal-title" translate>{{ 'plan_form.new_partner' }}</h3>
|
||||
</div>
|
||||
<div class="modal-body m-lg">
|
||||
<form name="partnerForm">
|
||||
|
@ -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
|
||||
|
||||
|
@ -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!
|
||||
|
||||
@ -31,7 +34,7 @@ class API::AdminsController < API::ApiController
|
||||
|
||||
def destroy
|
||||
@admin = User.admins.find(params[:id])
|
||||
if current_user.is_admin? and @admin != current_user
|
||||
if current_user.admin? && @admin != current_user
|
||||
@admin.destroy
|
||||
head :no_content
|
||||
else
|
||||
|
@ -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
|
||||
@ -19,7 +22,6 @@ class API::AgeRangesController < API::ApiController
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def update
|
||||
authorize AgeRange
|
||||
if @age_range.update(age_range_params)
|
||||
@ -39,6 +41,7 @@ class API::AgeRangesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_age_range
|
||||
@age_range = AgeRange.find(params[:id])
|
||||
end
|
||||
|
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class API::ApiController < ApplicationController
|
||||
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type AuthProvider
|
||||
# AuthProvider are used to connect users through single-sign on systems
|
||||
class API::AuthProvidersController < API::ApiController
|
||||
|
||||
before_action :set_provider, only: [:show, :update, :destroy]
|
||||
before_action :set_provider, only: %i[show update destroy]
|
||||
def index
|
||||
@providers = policy_scope(AuthProvider)
|
||||
end
|
||||
@ -57,33 +61,33 @@ class API::AuthProvidersController < API::ApiController
|
||||
NotificationCenter.call type: 'notify_user_auth_migration',
|
||||
receiver: user,
|
||||
attached_object: user
|
||||
render json: {status: 'processing'}, status: :ok
|
||||
render json: { status: 'processing' }, status: :ok
|
||||
else
|
||||
render json: {status: 'error', error: I18n.t('members.current_authentication_method_no_code')}, status: :bad_request
|
||||
render json: { status: 'error', error: I18n.t('members.current_authentication_method_no_code') }, status: :bad_request
|
||||
end
|
||||
else
|
||||
render json: {status: 'error', error: I18n.t('members.requested_account_does_not_exists')}, status: :bad_request
|
||||
render json: { status: 'error', error: I18n.t('members.requested_account_does_not_exists') }, status: :bad_request
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_provider
|
||||
@provider = AuthProvider.find(params[:id])
|
||||
end
|
||||
def set_provider
|
||||
@provider = AuthProvider.find(params[:id])
|
||||
end
|
||||
|
||||
def provider_params
|
||||
if params['auth_provider']['providable_type'] == DatabaseProvider.name
|
||||
params.require(:auth_provider).permit(:name, :providable_type)
|
||||
elsif params['auth_provider']['providable_type'] == OAuth2Provider.name
|
||||
params.require(:auth_provider).permit(:name, :providable_type, providable_attributes: [
|
||||
:id, :base_url, :token_endpoint, :authorization_endpoint, :logout_endpoint, :profile_url, :client_id, :client_secret,
|
||||
o_auth2_mappings_attributes: [
|
||||
:id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type, :_destroy,
|
||||
transformation: [:type, :format, :true_value, :false_value, mapping: [:from, :to]]
|
||||
]
|
||||
])
|
||||
end
|
||||
def provider_params
|
||||
if params['auth_provider']['providable_type'] == DatabaseProvider.name
|
||||
params.require(:auth_provider).permit(:name, :providable_type)
|
||||
elsif params['auth_provider']['providable_type'] == OAuth2Provider.name
|
||||
params.require(:auth_provider)
|
||||
.permit(:name, :providable_type,
|
||||
providable_attributes: [:id, :base_url, :token_endpoint, :authorization_endpoint, :logout_endpoint,
|
||||
:profile_url, :client_id, :client_secret,
|
||||
o_auth2_mappings_attributes: [:id, :local_model, :local_field, :api_field,
|
||||
:api_endpoint, :api_data_type, :_destroy,
|
||||
transformation: [:type, :format, :true_value,
|
||||
:false_value, mapping: %i[from to]]]])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Availability
|
||||
class API::AvailabilitiesController < API::ApiController
|
||||
include FablabConfiguration
|
||||
|
||||
@ -10,94 +13,30 @@ class API::AvailabilitiesController < API::ApiController
|
||||
authorize Availability
|
||||
start_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:start])
|
||||
end_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:end]).end_of_day
|
||||
@availabilities = Availability.includes(:machines, :tags, :trainings, :spaces).where.not(available_type: 'event')
|
||||
@availabilities = Availability.includes(:machines, :tags, :trainings, :spaces)
|
||||
.where.not(available_type: 'event')
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
|
||||
if fablab_spaces_deactivated?
|
||||
@availabilities = @availabilities.where.not(available_type: 'space')
|
||||
end
|
||||
@availabilities = @availabilities.where.not(available_type: 'space') if fablab_spaces_deactivated?
|
||||
end
|
||||
|
||||
def public
|
||||
start_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:start])
|
||||
end_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:end]).end_of_day
|
||||
@reservations = Reservation.includes(:slots, user: [:profile]).references(:slots, :user)
|
||||
.where('slots.start_at >= ? AND slots.end_at <= ?', start_date, end_date)
|
||||
@reservations = Reservation.includes(:slots, user: [:profile])
|
||||
.references(:slots, :user)
|
||||
.where('slots.start_at >= ? AND slots.end_at <= ?', start_date, end_date)
|
||||
|
||||
# request for 1 single day
|
||||
if in_same_day(start_date, end_date)
|
||||
# trainings, events
|
||||
@training_and_event_availabilities = Availability.includes(:tags, :trainings, :event, :slots)
|
||||
.where(available_type: %w[training event])
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
# machines
|
||||
@machine_availabilities = Availability.includes(:tags, :machines)
|
||||
.where(available_type: 'machines')
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
@machine_slots = []
|
||||
@machine_availabilities.each do |a|
|
||||
a.machines.each do |machine|
|
||||
next unless params[:m]&.include?(machine.id.to_s)
|
||||
|
||||
((a.end_at - a.start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
machine: machine,
|
||||
title: machine.name
|
||||
)
|
||||
slot = verify_machine_is_reserved(slot, @reservations, current_user, '')
|
||||
@machine_slots << slot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# spaces
|
||||
@space_availabilities = Availability.includes(:tags, :spaces).where(available_type: 'space')
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
|
||||
@space_availabilities.where(available_id: params[:s]) if params[:s]
|
||||
|
||||
@space_slots = []
|
||||
@space_availabilities.each do |a|
|
||||
space = a.spaces.first
|
||||
((a.end_at - a.start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
space: space,
|
||||
title: space.name
|
||||
)
|
||||
slot = verify_space_is_reserved(slot, @reservations, current_user, '')
|
||||
@space_slots << slot
|
||||
end
|
||||
end
|
||||
@availabilities = [].concat(@training_and_event_availabilities).concat(@machine_slots).concat(@space_slots)
|
||||
|
||||
# request for many days (week or month)
|
||||
else
|
||||
@availabilities = Availability.includes(:tags, :machines, :trainings, :spaces, :event, :slots)
|
||||
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
|
||||
.where(lock: false)
|
||||
@availabilities.each do |a|
|
||||
if a.available_type == 'training' or a.available_type == 'event'
|
||||
a = verify_training_event_is_reserved(a, @reservations, current_user)
|
||||
elsif a.available_type == 'space'
|
||||
a.is_reserved = is_reserved_availability(a, current_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
machine_ids = params[:m] || []
|
||||
@title_filter = {machine_ids: machine_ids.map(&:to_i)}
|
||||
service = Availabilities::PublicAvailabilitiesService.new(current_user)
|
||||
@availabilities = service.public_availabilities(
|
||||
start_date,
|
||||
end_date,
|
||||
@reservations,
|
||||
machines: machine_ids, spaces: params[:s]
|
||||
)
|
||||
|
||||
@title_filter = { machine_ids: machine_ids.map(&:to_i) }
|
||||
@availabilities = filter_availabilites(@availabilities)
|
||||
end
|
||||
|
||||
@ -134,138 +73,22 @@ class API::AvailabilitiesController < API::ApiController
|
||||
end
|
||||
|
||||
def machine
|
||||
@user = if params[:member_id]
|
||||
User.find(params[:member_id])
|
||||
else
|
||||
current_user
|
||||
end
|
||||
@current_user_role = current_user.is_admin? ? 'admin' : 'user'
|
||||
@machine = Machine.friendly.find(params[:machine_id])
|
||||
@slots = []
|
||||
@reservations = Reservation.where('reservable_type = ? and reservable_id = ?', @machine.class.to_s, @machine.id)
|
||||
.includes(:slots, user: [:profile])
|
||||
.references(:slots, :user)
|
||||
.where('slots.start_at > ?', Time.now)
|
||||
if @user.is_admin?
|
||||
@availabilities = @machine.availabilities.includes(:tags)
|
||||
.where("end_at > ? AND available_type = 'machines'", Time.now)
|
||||
.where(lock: false)
|
||||
else
|
||||
end_at = @visi_max_other
|
||||
end_at = @visi_max_year if is_subscription_year(@user)
|
||||
@availabilities = @machine.availabilities
|
||||
.includes(:tags)
|
||||
.where("end_at > ? AND end_at < ? AND available_type = 'machines'", Time.now, end_at)
|
||||
.where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
||||
.where(lock: false)
|
||||
end
|
||||
@availabilities.each do |a|
|
||||
((a.end_at - a.start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
@current_user_role = current_user.admin? ? 'admin' : 'user'
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
machine: @machine,
|
||||
title: ''
|
||||
)
|
||||
slot = verify_machine_is_reserved(slot, @reservations, current_user, @current_user_role)
|
||||
@slots << slot
|
||||
end
|
||||
end
|
||||
service = Availabilities::AvailabilitiesService.new(current_user, other: @visi_max_other, year: @visi_max_year)
|
||||
@slots = service.machines(params[:machine_id], user)
|
||||
end
|
||||
|
||||
def trainings
|
||||
@user = if params[:member_id]
|
||||
User.find(params[:member_id])
|
||||
else
|
||||
current_user
|
||||
end
|
||||
@slots = []
|
||||
|
||||
# first, we get the already-made reservations
|
||||
@reservations = @user.reservations.where("reservable_type = 'Training'")
|
||||
@reservations = @reservations.where('reservable_id = :id', id: params[:training_id].to_i) if params[:training_id].is_number?
|
||||
@reservations = @reservations.joins(:slots).where('slots.start_at > ?', Time.now)
|
||||
|
||||
# what is requested?
|
||||
# 1) a single training
|
||||
@availabilities = if params[:training_id].is_number? or (params[:training_id].length > 0 and params[:training_id] != 'all')
|
||||
Training.friendly.find(params[:training_id]).availabilities
|
||||
# 2) all trainings
|
||||
else
|
||||
Availability.trainings
|
||||
end
|
||||
|
||||
# who made the request?
|
||||
# 1) an admin (he can see all future availabilities)
|
||||
if current_user.is_admin?
|
||||
@availabilities = @availabilities.includes(:tags, :slots, trainings: [:machines])
|
||||
.where('availabilities.start_at > ?', Time.now)
|
||||
.where(lock: false)
|
||||
# 2) an user (he cannot see availabilities further than 1 (or 3) months)
|
||||
else
|
||||
end_at = @visi_max_year
|
||||
end_at = @visi_max_year if can_show_slot_plus_three_months(@user)
|
||||
@availabilities = @availabilities.includes(:tags, :slots, :availability_tags, trainings: [:machines])
|
||||
.where('availabilities.start_at > ? AND availabilities.start_at < ?', Time.now, end_at)
|
||||
.where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
||||
.where(lock: false)
|
||||
end
|
||||
|
||||
# finally, we merge the availabilities with the reservations
|
||||
@availabilities.each do |a|
|
||||
a = verify_training_event_is_reserved(a, @reservations, @user)
|
||||
end
|
||||
service = Availabilities::AvailabilitiesService.new(current_user, other: @visi_max_other, year: @visi_max_year)
|
||||
@availabilities = service.trainings(params[:training_id], user)
|
||||
end
|
||||
|
||||
def spaces
|
||||
@user = if params[:member_id]
|
||||
User.find(params[:member_id])
|
||||
else
|
||||
current_user
|
||||
end
|
||||
@current_user_role = current_user.is_admin? ? 'admin' : 'user'
|
||||
@space = Space.friendly.find(params[:space_id])
|
||||
@slots = []
|
||||
@reservations = Reservation.where('reservable_type = ? and reservable_id = ?', @space.class.to_s, @space.id)
|
||||
.includes(:slots, user: [:profile]).references(:slots, :user)
|
||||
.where('slots.start_at > ?', Time.now)
|
||||
if current_user.is_admin?
|
||||
@availabilities = @space.availabilities.includes(:tags)
|
||||
.where("end_at > ? AND available_type = 'space'", Time.now)
|
||||
.where(lock: false)
|
||||
else
|
||||
end_at = @visi_max_other
|
||||
end_at = @visi_max_year if is_subscription_year(@user)
|
||||
@availabilities = @space.availabilities.includes(:tags)
|
||||
.where("end_at > ? AND end_at < ? AND available_type = 'space'", Time.now, end_at)
|
||||
.where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
||||
.where(lock: false)
|
||||
end
|
||||
@availabilities.each do |a|
|
||||
((a.end_at - a.start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
|
||||
next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > Time.now
|
||||
@current_user_role = current_user.admin? ? 'admin' : 'user'
|
||||
|
||||
slot = Slot.new(
|
||||
start_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes,
|
||||
end_at: a.start_at + (i*ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
|
||||
availability_id: a.id,
|
||||
availability: a,
|
||||
space: @space,
|
||||
title: ''
|
||||
)
|
||||
slot = verify_space_is_reserved(slot, @reservations, @user, @current_user_role)
|
||||
@slots << slot
|
||||
end
|
||||
end
|
||||
@slots.each do |s|
|
||||
if s.is_complete? and not s.is_reserved
|
||||
s.title = t('availabilities.not_available')
|
||||
end
|
||||
end
|
||||
service = Availabilities::AvailabilitiesService.new(current_user, other: @visi_max_other, year: @visi_max_year)
|
||||
@slots = service.spaces(params[:space_id], user)
|
||||
end
|
||||
|
||||
def reservations
|
||||
@ -281,7 +104,7 @@ class API::AvailabilitiesController < API::ApiController
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new(category: 'availabilities', export_type: 'index', user: current_user)
|
||||
if @export.save
|
||||
render json: {export_id: @export.id}, status: :ok
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
render json: @export.errors, status: :unprocessable_entity
|
||||
end
|
||||
@ -303,6 +126,14 @@ class API::AvailabilitiesController < API::ApiController
|
||||
|
||||
private
|
||||
|
||||
def user
|
||||
if params[:member_id]
|
||||
User.find(params[:member_id])
|
||||
else
|
||||
current_user
|
||||
end
|
||||
end
|
||||
|
||||
def set_availability
|
||||
@availability = Availability.find(params[:id])
|
||||
end
|
||||
@ -317,104 +148,6 @@ class API::AvailabilitiesController < API::ApiController
|
||||
params.require(:lock)
|
||||
end
|
||||
|
||||
def is_reserved_availability(availability, user)
|
||||
if user
|
||||
reserved_slots = []
|
||||
availability.slots.each do |s|
|
||||
if s.canceled_at.nil?
|
||||
reserved_slots << s
|
||||
end
|
||||
end
|
||||
reserved_slots.map(&:reservations).flatten.map(&:user_id).include? user.id
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def is_reserved(start_at, reservations)
|
||||
is_reserved = false
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
is_reserved = true if s.start_at == start_at
|
||||
end
|
||||
end
|
||||
is_reserved
|
||||
end
|
||||
|
||||
def verify_machine_is_reserved(slot, reservations, user, user_role)
|
||||
show_name = (user_role == 'admin' or Setting.find_by(name: 'display_name_enable').value == 'true')
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless slot.machine.id == r.reservable_id
|
||||
|
||||
if s.start_at == slot.start_at and s.canceled_at == nil
|
||||
slot.id = s.id
|
||||
slot.is_reserved = true
|
||||
slot.title = "#{slot.machine.name} - #{show_name ? r.user.profile.full_name : t('availabilities.not_available')}"
|
||||
slot.can_modify = true if user_role === 'admin'
|
||||
slot.reservations.push r
|
||||
end
|
||||
if s.start_at == slot.start_at and r.user == user and s.canceled_at == nil
|
||||
slot.title = "#{slot.machine.name} - #{t('availabilities.i_ve_reserved')}"
|
||||
slot.can_modify = true
|
||||
slot.is_reserved_by_current_user = true
|
||||
end
|
||||
end
|
||||
end
|
||||
slot
|
||||
end
|
||||
|
||||
def verify_space_is_reserved(slot, reservations, user, user_role)
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless slot.space.id == r.reservable_id
|
||||
|
||||
if s.start_at == slot.start_at and s.canceled_at == nil
|
||||
slot.can_modify = true if user_role === 'admin'
|
||||
slot.reservations.push r
|
||||
end
|
||||
if s.start_at == slot.start_at and r.user == user and s.canceled_at == nil
|
||||
slot.id = s.id
|
||||
slot.title = t('availabilities.i_ve_reserved')
|
||||
slot.can_modify = true
|
||||
slot.is_reserved = true
|
||||
end
|
||||
end
|
||||
end
|
||||
slot
|
||||
end
|
||||
|
||||
def verify_training_event_is_reserved(availability, reservations, user)
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
next unless (
|
||||
(availability.available_type == 'training' && availability.trainings.first.id == r.reservable_id) ||
|
||||
(availability.available_type == 'event' && availability.event.id == r.reservable_id)
|
||||
) && s.start_at == availability.start_at && s.canceled_at == nil
|
||||
|
||||
availability.slot_id = s.id
|
||||
if r.user == user
|
||||
availability.is_reserved = true
|
||||
availability.can_modify = true
|
||||
end
|
||||
end
|
||||
end
|
||||
availability
|
||||
end
|
||||
|
||||
def can_show_slot_plus_three_months(user)
|
||||
# member must have validated at least 1 training and must have a valid yearly subscription.
|
||||
user.trainings.size > 0 and is_subscription_year(user)
|
||||
end
|
||||
|
||||
def is_subscription_year(user)
|
||||
user.subscription and user.subscription.plan.interval == 'year' and user.subscription.expired_at >= Time.now
|
||||
end
|
||||
|
||||
def in_same_day(start_date, end_date)
|
||||
(end_date.to_date - start_date.to_date).to_i == 1
|
||||
end
|
||||
|
||||
def filter_availabilites(availabilities)
|
||||
availabilities_filtered = []
|
||||
availabilities.to_ary.each do |a|
|
||||
@ -422,35 +155,33 @@ class API::AvailabilitiesController < API::ApiController
|
||||
if !a.try(:available_type)
|
||||
availabilities_filtered << a
|
||||
else
|
||||
# training
|
||||
if params[:t] and a.available_type == 'training'
|
||||
if params[:t].include?(a.trainings.first.id.to_s)
|
||||
availabilities_filtered << a
|
||||
end
|
||||
end
|
||||
# space
|
||||
if params[:s] and a.available_type == 'space'
|
||||
if params[:s].include?(a.spaces.first.id.to_s)
|
||||
availabilities_filtered << a
|
||||
end
|
||||
end
|
||||
# machines
|
||||
if params[:m] and a.available_type == 'machines'
|
||||
if (params[:m].map(&:to_i) & a.machine_ids).any?
|
||||
availabilities_filtered << a
|
||||
end
|
||||
end
|
||||
# event
|
||||
if params[:evt] and params[:evt] == 'true' and a.available_type == 'event'
|
||||
availabilities_filtered << a
|
||||
end
|
||||
end
|
||||
end
|
||||
availabilities_filtered.delete_if do |a|
|
||||
if params[:dispo] == 'false'
|
||||
a.is_reserved or (a.try(:completed?) and a.completed?)
|
||||
availabilities_filtered << a if filter_training?(a)
|
||||
availabilities_filtered << a if filter_space?(a)
|
||||
availabilities_filtered << a if filter_machine?(a)
|
||||
availabilities_filtered << a if filter_event?(a)
|
||||
end
|
||||
end
|
||||
availabilities_filtered.delete_if(&method(:remove_completed?))
|
||||
end
|
||||
|
||||
def filter_training?(availability)
|
||||
params[:t] && availability.available_type == 'training' && params[:t].include?(availability.trainings.first.id.to_s)
|
||||
end
|
||||
|
||||
def filter_space?(availability)
|
||||
params[:s] && availability.available_type == 'space' && params[:s].include?(availability.spaces.first.id.to_s)
|
||||
end
|
||||
|
||||
def filter_machine?(availability)
|
||||
params[:m] && availability.available_type == 'machines' && (params[:m].map(&:to_i) & availability.machine_ids).any?
|
||||
end
|
||||
|
||||
def filter_event?(availability)
|
||||
params[:evt] && params[:evt] == 'true' && availability.available_type == 'event'
|
||||
end
|
||||
|
||||
def remove_completed?(availability)
|
||||
params[:dispo] == 'false' && (availability.is_reserved || (availability.try(:completed?) && availability.completed?))
|
||||
end
|
||||
|
||||
def define_max_visibility
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Category
|
||||
# Categories are used to classify Events
|
||||
class API::CategoriesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index]
|
||||
before_action :set_category, only: [:show, :update, :destroy]
|
||||
before_action :set_category, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@categories = Category.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Category
|
||||
@ -39,11 +42,12 @@ class API::CategoriesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_category
|
||||
@category = Category.find(params[:id])
|
||||
end
|
||||
|
||||
def category_params
|
||||
params.require(:category).permit(:name)
|
||||
end
|
||||
def set_category
|
||||
@category = Category.find(params[:id])
|
||||
end
|
||||
|
||||
def category_params
|
||||
params.require(:category).permit(:name)
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Component
|
||||
# Components are used in Projects
|
||||
class API::ComponentsController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_component, only: [:show, :update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_component, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@components = Component.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Component
|
||||
@ -35,11 +38,12 @@ class API::ComponentsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_component
|
||||
@component = Component.find(params[:id])
|
||||
end
|
||||
|
||||
def component_params
|
||||
params.require(:component).permit(:name)
|
||||
end
|
||||
def set_component
|
||||
@component = Component.find(params[:id])
|
||||
end
|
||||
|
||||
def component_params
|
||||
params.require(:component).permit(:name)
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Coupon
|
||||
# Coupons are used in payments
|
||||
class API::CouponsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_coupon, only: [:show, :update, :destroy]
|
||||
before_action :set_coupon, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@coupons = Coupon.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Coupon
|
||||
@ -22,18 +25,18 @@ class API::CouponsController < API::ApiController
|
||||
def validate
|
||||
@coupon = Coupon.find_by(code: params[:code])
|
||||
if @coupon.nil?
|
||||
render json: {status: 'rejected'}, status: :not_found
|
||||
render json: { status: 'rejected' }, status: :not_found
|
||||
else
|
||||
if !current_user.is_admin?
|
||||
_user_id = current_user.id
|
||||
else
|
||||
_user_id = params[:user_id]
|
||||
end
|
||||
_user_id = if !current_user.admin?
|
||||
current_user.id
|
||||
else
|
||||
params[:user_id]
|
||||
end
|
||||
|
||||
amount = params[:amount].to_f * 100.0
|
||||
status = @coupon.status(_user_id, amount)
|
||||
if status != 'active'
|
||||
render json: {status: status}, status: :unprocessable_entity
|
||||
render json: { status: status }, status: :unprocessable_entity
|
||||
else
|
||||
render :validate, status: :ok, location: @coupon
|
||||
end
|
||||
@ -62,18 +65,17 @@ class API::CouponsController < API::ApiController
|
||||
authorize Coupon
|
||||
|
||||
@coupon = Coupon.find_by(code: params[:coupon_code])
|
||||
if @coupon.nil?
|
||||
render json: {error: "no coupon with code #{params[:coupon_code]}"}, status: :not_found
|
||||
else
|
||||
if @coupon.send_to(params[:user_id])
|
||||
render :show, status: :ok, location: @coupon
|
||||
else
|
||||
render json: @coupon.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
if @coupon.nil?
|
||||
render json: { error: "no coupon with code #{params[:coupon_code]}" }, status: :not_found
|
||||
elsif @coupon.send_to(params[:user_id])
|
||||
render :show, status: :ok, location: @coupon
|
||||
else
|
||||
render json: @coupon.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_coupon
|
||||
@coupon = Coupon.find(params[:id])
|
||||
end
|
||||
@ -85,7 +87,8 @@ class API::CouponsController < API::ApiController
|
||||
@parameters = params
|
||||
@parameters[:coupon][:amount_off] = @parameters[:coupon][:amount_off].to_f * 100.0 if @parameters[:coupon][:amount_off]
|
||||
|
||||
@parameters = @parameters.require(:coupon).permit(:name, :code, :percent_off, :amount_off, :validity_per_user, :valid_until, :max_usages, :active)
|
||||
@parameters = @parameters.require(:coupon).permit(:name, :code, :percent_off, :amount_off, :validity_per_user, :valid_until,
|
||||
:max_usages, :active)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,14 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Credit
|
||||
# Credits are used to give free reservations to users
|
||||
class API::CreditsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_credit, only: [:show, :update, :destroy]
|
||||
before_action :set_credit, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
authorize Credit
|
||||
if params
|
||||
@credits = Credit.includes(:creditable).where(params.permit(:creditable_type))
|
||||
else
|
||||
@credits = Credit.includes(:creditable).all
|
||||
end
|
||||
@credits = if params
|
||||
Credit.includes(:creditable).where(params.permit(:creditable_type))
|
||||
else
|
||||
Credit.includes(:creditable).all
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@ -37,11 +41,12 @@ class API::CreditsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_credit
|
||||
@credit = Credit.find(params[:id])
|
||||
end
|
||||
|
||||
def credit_params
|
||||
params.require(:credit).permit!
|
||||
end
|
||||
def set_credit
|
||||
@credit = Credit.find(params[:id])
|
||||
end
|
||||
|
||||
def credit_params
|
||||
params.require(:credit).permit!
|
||||
end
|
||||
end
|
||||
|
@ -1,10 +1,10 @@
|
||||
class API::CustomAssetsController < API::ApiController
|
||||
before_action :authenticate_user!, only: [:index, :update, :create, :destroy]
|
||||
before_action :set_custom_asset, only: [:show, :update, :destroy]
|
||||
# frozen_string_literal: true
|
||||
|
||||
def index
|
||||
#TODO GET /api/custom_assets/
|
||||
end
|
||||
# API Controller for resources of type CustomAsset
|
||||
# CustomAssets are used in settings
|
||||
class API::CustomAssetsController < API::ApiController
|
||||
before_action :authenticate_user!, only: %i[index update create destroy]
|
||||
before_action :set_custom_asset, only: %i[show update destroy]
|
||||
|
||||
# PUT /api/custom_assets/1/
|
||||
def update
|
||||
@ -28,14 +28,10 @@ class API::CustomAssetsController < API::ApiController
|
||||
end
|
||||
|
||||
# GET /api/custom_assets/1/
|
||||
def show
|
||||
end
|
||||
|
||||
def destroy
|
||||
#TODO DELETE /api/custom_assets/1/
|
||||
end
|
||||
def show; end
|
||||
|
||||
private
|
||||
|
||||
def set_custom_asset
|
||||
@custom_asset = CustomAsset.find_by(name: params[:id])
|
||||
end
|
||||
@ -45,4 +41,4 @@ class API::CustomAssetsController < API::ApiController
|
||||
params.required(:custom_asset).permit(:name, custom_asset_file_attributes: [:attachment])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type EventTheme
|
||||
# EventTheme are used to classify Events
|
||||
class API::EventThemesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index]
|
||||
before_action :set_event_theme, only: [:show, :update, :destroy]
|
||||
before_action :set_event_theme, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@event_themes = EventTheme.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize EventTheme
|
||||
@ -39,6 +42,7 @@ class API::EventThemesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_event_theme
|
||||
@event_theme = EventTheme.find(params[:id])
|
||||
end
|
||||
|
@ -1,5 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Event
|
||||
class API::EventsController < API::ApiController
|
||||
before_action :set_event, only: [:show, :update, :destroy]
|
||||
before_action :set_event, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@events = policy_scope(Event)
|
||||
@ -11,17 +14,17 @@ class API::EventsController < API::ApiController
|
||||
@events = @events.joins(:event_themes).where('event_themes.id = :theme', theme: params[:theme_id]) if params[:theme_id]
|
||||
@events = @events.where('age_range_id = :age_range', age_range: params[:age_range_id]) if params[:age_range_id]
|
||||
|
||||
if current_user and current_user.is_admin?
|
||||
case params[:scope]
|
||||
when 'future'
|
||||
@events = @events.where('availabilities.start_at >= ?', Time.now).order('availabilities.start_at DESC')
|
||||
when 'future_asc'
|
||||
@events = @events.where('availabilities.start_at >= ?', Time.now).order('availabilities.start_at ASC')
|
||||
when 'passed'
|
||||
@events = @events.where('availabilities.start_at < ?', Time.now).order('availabilities.start_at DESC')
|
||||
else
|
||||
@events = @events.order('availabilities.start_at DESC')
|
||||
end
|
||||
if current_user&.admin?
|
||||
@events = case params[:scope]
|
||||
when 'future'
|
||||
@events.where('availabilities.start_at >= ?', Time.now).order('availabilities.start_at DESC')
|
||||
when 'future_asc'
|
||||
@events.where('availabilities.start_at >= ?', Time.now).order('availabilities.start_at ASC')
|
||||
when 'passed'
|
||||
@events.where('availabilities.start_at < ?', Time.now).order('availabilities.start_at DESC')
|
||||
else
|
||||
@events.order('availabilities.start_at DESC')
|
||||
end
|
||||
end
|
||||
|
||||
# paginate
|
||||
@ -38,8 +41,7 @@ class API::EventsController < API::ApiController
|
||||
.limit(limit)
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Event
|
||||
@ -61,9 +63,10 @@ class API::EventsController < API::ApiController
|
||||
end
|
||||
rescue ActiveRecord::RecordNotDestroyed => e
|
||||
if e.record.class.name == 'EventPriceCategory'
|
||||
render json: {error: ["#{e.record.price_category.name}: #{t('events.error_deleting_reserved_price')}"]}, status: :unprocessable_entity
|
||||
render json: { error: ["#{e.record.price_category.name}: #{t('events.error_deleting_reserved_price')}"] },
|
||||
status: :unprocessable_entity
|
||||
else
|
||||
render json: {error: [t('events.other_error')]}, status: :unprocessable_entity
|
||||
render json: { error: [t('events.other_error')] }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@ -79,48 +82,22 @@ class API::EventsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_event
|
||||
@event = Event.find(params[:id])
|
||||
end
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def event_params
|
||||
# handle general properties
|
||||
event_preparams = params.required(:event).permit(:title, :description, :start_date, :start_time, :end_date, :end_time,
|
||||
:amount, :nb_total_places, :availability_id,
|
||||
:all_day, :recurrence, :recurrence_end_at, :category_id, :event_theme_ids,
|
||||
:age_range_id, event_theme_ids: [],
|
||||
event_image_attributes: [:attachment],
|
||||
event_files_attributes: [:id, :attachment, :_destroy],
|
||||
event_price_categories_attributes: [:id, :price_category_id, :amount, :_destroy]
|
||||
)
|
||||
# handle dates & times (whole-day events or not, maybe during many days)
|
||||
start_date = Time.zone.parse(event_preparams[:start_date])
|
||||
end_date = Time.zone.parse(event_preparams[:end_date])
|
||||
start_time = Time.parse(event_preparams[:start_time]) if event_preparams[:start_time]
|
||||
end_time = Time.parse(event_preparams[:end_time]) if event_preparams[:end_time]
|
||||
if event_preparams[:all_day] == 'true'
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, 0, 0, 0, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, 23, 59, 59, end_date.zone)
|
||||
else
|
||||
start_at = DateTime.new(start_date.year, start_date.month, start_date.day, start_time.hour, start_time.min, start_time.sec, start_date.zone)
|
||||
end_at = DateTime.new(end_date.year, end_date.month, end_date.day, end_time.hour, end_time.min, end_time.sec, end_date.zone)
|
||||
end
|
||||
event_preparams.merge!(availability_attributes: {id: event_preparams[:availability_id], start_at: start_at, end_at: end_at, available_type: 'event'})
|
||||
.except!(:start_date, :end_date, :start_time, :end_time, :all_day)
|
||||
# convert main price to centimes
|
||||
event_preparams.merge!(amount: (event_preparams[:amount].to_f * 100 if event_preparams[:amount].present?))
|
||||
# delete non-complete "other" prices and convert them to centimes
|
||||
unless event_preparams[:event_price_categories_attributes].nil?
|
||||
event_preparams[:event_price_categories_attributes].delete_if { |price_cat| price_cat[:price_category_id].empty? or price_cat[:amount].empty? }
|
||||
event_preparams[:event_price_categories_attributes].each do |price_cat|
|
||||
price_cat[:amount] = price_cat[:amount].to_f * 100
|
||||
end
|
||||
end
|
||||
# return the resulting params object
|
||||
event_preparams
|
||||
end
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_event
|
||||
@event = Event.find(params[:id])
|
||||
end
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def event_params
|
||||
# handle general properties
|
||||
event_preparams = params.required(:event).permit(:title, :description, :start_date, :start_time, :end_date, :end_time,
|
||||
:amount, :nb_total_places, :availability_id, :all_day, :recurrence,
|
||||
:recurrence_end_at, :category_id, :event_theme_ids, :age_range_id,
|
||||
event_theme_ids: [],
|
||||
event_image_attributes: [:attachment],
|
||||
event_files_attributes: %i[id attachment_destroy],
|
||||
event_price_categories_attributes: %i[id price_category_id amount _destroy])
|
||||
EventService.process_params(event_preparams)
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Export
|
||||
# Export are used to download data tables in offline files
|
||||
class API::ExportsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_export, only: [:download]
|
||||
@ -6,7 +10,9 @@ class API::ExportsController < API::ApiController
|
||||
authorize @export
|
||||
|
||||
if FileTest.exist?(@export.file)
|
||||
send_file File.join(Rails.root, @export.file), :type => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :disposition => 'attachment'
|
||||
send_file File.join(Rails.root, @export.file),
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
disposition: 'attachment'
|
||||
else
|
||||
render text: I18n.t('errors.messages.export_not_found'), status: :not_found
|
||||
end
|
||||
@ -15,38 +21,39 @@ class API::ExportsController < API::ApiController
|
||||
def status
|
||||
authorize Export
|
||||
|
||||
export = Export.where({category: params[:category], export_type: params[:type], query: params[:query], key: params[:key]})
|
||||
export = Export.where(category: params[:category], export_type: params[:type], query: params[:query], key: params[:key])
|
||||
|
||||
if params[:category] === 'users'
|
||||
if params[:category] == 'users'
|
||||
case params[:type]
|
||||
when 'subscriptions'
|
||||
export = export.where('created_at > ?', Subscription.maximum('updated_at'))
|
||||
when 'reservations'
|
||||
export = export.where('created_at > ?', Reservation.maximum('updated_at'))
|
||||
when 'members'
|
||||
export = export.where('created_at > ?', User.with_role(:member).maximum('updated_at'))
|
||||
else
|
||||
raise ArgumentError, "Unknown export users/#{params[:type]}"
|
||||
when 'subscriptions'
|
||||
export = export.where('created_at > ?', Subscription.maximum('updated_at'))
|
||||
when 'reservations'
|
||||
export = export.where('created_at > ?', Reservation.maximum('updated_at'))
|
||||
when 'members'
|
||||
export = export.where('created_at > ?', User.with_role(:member).maximum('updated_at'))
|
||||
else
|
||||
raise ArgumentError, "Unknown export users/#{params[:type]}"
|
||||
end
|
||||
elsif params[:category] === 'availabilities'
|
||||
elsif params[:category] == 'availabilities'
|
||||
case params[:type]
|
||||
when 'index'
|
||||
export = export.where('created_at > ?', Availability.maximum('updated_at'))
|
||||
else
|
||||
raise ArgumentError, "Unknown type availabilities/#{params[:type]}"
|
||||
when 'index'
|
||||
export = export.where('created_at > ?', Availability.maximum('updated_at'))
|
||||
else
|
||||
raise ArgumentError, "Unknown type availabilities/#{params[:type]}"
|
||||
end
|
||||
end
|
||||
export = export.last
|
||||
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
render json: {exists: false, id: nil}, status: :ok
|
||||
render json: { exists: false, id: nil }, status: :ok
|
||||
else
|
||||
render json: {exists: true, id: export.id}, status: :ok
|
||||
render json: { exists: true, id: export.id }, status: :ok
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_export
|
||||
@export = Export.find(params[:id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,16 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller to wrap social networks public feeds
|
||||
class API::FeedsController < API::ApiController
|
||||
|
||||
respond_to :json
|
||||
|
||||
def twitter_timelines
|
||||
if params
|
||||
limit = params[:limit]
|
||||
else
|
||||
limit = 3
|
||||
end
|
||||
limit = if params
|
||||
params[:limit]
|
||||
else
|
||||
3
|
||||
end
|
||||
from_account = Setting.find_by(name: 'twitter_name').try(:value) || ENV['TWITTER_NAME']
|
||||
begin
|
||||
@tweet_news = Feed.twitter.user_timeline(from_account, {count: limit})
|
||||
@tweet_news = Feed.twitter.user_timeline(from_account, count: limit)
|
||||
rescue Twitter::Error::BadRequest => e
|
||||
STDERR.puts "[WARNING] Unable to retrieve the twitter feed, please check your ENV configuration. Details: #{e.message}"
|
||||
render status: :no_content
|
||||
|
@ -1,12 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Group
|
||||
# Groups are used for categorizing Users
|
||||
class API::GroupsController < API::ApiController
|
||||
before_action :authenticate_user!, except: :index
|
||||
|
||||
def index
|
||||
if current_user and current_user.is_admin?
|
||||
@groups = Group.all
|
||||
else
|
||||
@groups = Group.where.not(slug: 'admins')
|
||||
end
|
||||
@groups = if current_user&.admin?
|
||||
Group.all
|
||||
else
|
||||
Group.where.not(slug: 'admins')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -39,7 +43,7 @@ class API::GroupsController < API::ApiController
|
||||
|
||||
private
|
||||
|
||||
def group_params
|
||||
params.require(:group).permit(:name, :disabled)
|
||||
end
|
||||
def group_params
|
||||
params.require(:group).permit(:name, :disabled)
|
||||
end
|
||||
end
|
||||
|
@ -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,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Licence
|
||||
# Licenses are used in Projects
|
||||
class API::LicencesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_licence, only: [:show, :update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_licence, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@licences = Licence.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize Licence
|
||||
@ -35,11 +38,12 @@ class API::LicencesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_licence
|
||||
@licence = Licence.find(params[:id])
|
||||
end
|
||||
|
||||
def licence_params
|
||||
params.require(:licence).permit(:name, :description)
|
||||
end
|
||||
def set_licence
|
||||
@licence = Licence.find(params[:id])
|
||||
end
|
||||
|
||||
def licence_params
|
||||
params.require(:licence).permit(:name, :description)
|
||||
end
|
||||
end
|
||||
|
@ -1,15 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Machine
|
||||
class API::MachinesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :set_machine, only: [:update, :destroy]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
before_action :set_machine, only: %i[update destroy]
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
sort_by = Setting.find_by(name: 'machines_sort_by').value || 'default'
|
||||
if sort_by === 'default'
|
||||
@machines = Machine.includes(:machine_image, :plans)
|
||||
else
|
||||
@machines = Machine.includes(:machine_image, :plans).order(sort_by)
|
||||
end
|
||||
@machines = if sort_by == 'default'
|
||||
Machine.includes(:machine_image, :plans)
|
||||
else
|
||||
Machine.includes(:machine_image, :plans).order(sort_by)
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@ -42,22 +45,14 @@ class API::MachinesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def set_machine
|
||||
@machine = Machine.find(params[:id])
|
||||
end
|
||||
|
||||
def machine_params
|
||||
params.require(:machine).permit(:name, :description, :spec, :disabled, :plan_ids, plan_ids: [], machine_image_attributes: [:attachment],
|
||||
machine_files_attributes: [:id, :attachment, :_destroy])
|
||||
end
|
||||
def set_machine
|
||||
@machine = Machine.find(params[:id])
|
||||
end
|
||||
|
||||
def is_reserved(start_at, reservations)
|
||||
is_reserved = false
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
is_reserved = true if s.start_at == start_at
|
||||
end
|
||||
end
|
||||
is_reserved
|
||||
end
|
||||
def machine_params
|
||||
params.require(:machine).permit(:name, :description, :spec, :disabled, :plan_ids,
|
||||
plan_ids: [], machine_image_attributes: [:attachment],
|
||||
machine_files_attributes: %i[id attachment _destroy])
|
||||
end
|
||||
end
|
||||
|
@ -1,15 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type User with role 'member'
|
||||
class API::MembersController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:last_subscribed]
|
||||
before_action :set_member, only: [:update, :destroy, :merge]
|
||||
before_action :set_member, only: %i[update destroy merge]
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@requested_attributes = params[:requested_attributes]
|
||||
@query = policy_scope(User)
|
||||
|
||||
unless params[:page].nil? and params[:size].nil?
|
||||
@query = @query.page(params[:page].to_i).per(params[:size].to_i)
|
||||
end
|
||||
@query = @query.page(params[:page].to_i).per(params[:size].to_i) unless params[:page].nil? && params[:size].nil?
|
||||
|
||||
# remove unmerged profiles from list
|
||||
@members = @query.to_a
|
||||
@ -17,7 +18,11 @@ class API::MembersController < API::ApiController
|
||||
end
|
||||
|
||||
def last_subscribed
|
||||
@query = User.active.with_role(:member).includes(profile: [:user_avatar]).where('is_allow_contact = true AND confirmed_at IS NOT NULL').order('created_at desc').limit(params[:last])
|
||||
@query = User.active.with_role(:member)
|
||||
.includes(profile: [:user_avatar])
|
||||
.where('is_allow_contact = true AND confirmed_at IS NOT NULL')
|
||||
.order('created_at desc')
|
||||
.limit(params[:last])
|
||||
|
||||
# remove unmerged profiles from list
|
||||
@members = @query.to_a
|
||||
@ -34,27 +39,11 @@ class API::MembersController < API::ApiController
|
||||
|
||||
def create
|
||||
authorize User
|
||||
if !user_params[:password] and !user_params[:password_confirmation]
|
||||
generated_password = Devise.friendly_token.first(8)
|
||||
@member = User.new(user_params.merge(password: generated_password).permit!)
|
||||
else
|
||||
@member = User.new(user_params.permit!)
|
||||
end
|
||||
|
||||
@member = User.new(user_params.permit!)
|
||||
members_service = Members::MembersService.new(@member)
|
||||
|
||||
# if the user is created by an admin and the authentication is made through an SSO, generate a migration token
|
||||
if current_user.is_admin? and AuthProvider.active.providable_type != DatabaseProvider.name
|
||||
@member.generate_auth_migration_token
|
||||
end
|
||||
|
||||
if @member.save
|
||||
@member.generate_subscription_invoice
|
||||
@member.send_confirmation_instructions
|
||||
if !user_params[:password] and !user_params[:password_confirmation]
|
||||
UsersMailer.delay.notify_user_account_created(@member, generated_password)
|
||||
else
|
||||
UsersMailer.delay.notify_user_account_created(@member, user_params[:password])
|
||||
end
|
||||
if members_service.create(current_user, user_params)
|
||||
render :show, status: :created, location: member_path(@member)
|
||||
else
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
@ -63,21 +52,14 @@ class API::MembersController < API::ApiController
|
||||
|
||||
def update
|
||||
authorize @member
|
||||
members_service = MembersService.new(@member)
|
||||
members_service = Members::MembersService.new(@member)
|
||||
|
||||
if user_params[:group_id] && @member.group_id != user_params[:group_id].to_i && !@member.subscribed_plan.nil?
|
||||
# here a group change is requested but unprocessable, handle the exception
|
||||
@member.errors[:group_id] = t('members.unable_to_change_the_group_while_a_subscription_is_running')
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
if members_service.update(user_params)
|
||||
# Update password without logging out
|
||||
sign_in(@member, bypass: true) unless current_user.id != params[:id].to_i
|
||||
render :show, status: :ok, location: member_path(@member)
|
||||
else
|
||||
# otherwise, run the user update
|
||||
if members_service.update(user_params)
|
||||
# Update password without logging out
|
||||
sign_in(@member, bypass: true) unless current_user.id != params[:id].to_i
|
||||
render :show, status: :ok, location: member_path(@member)
|
||||
else
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
end
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@ -92,9 +74,11 @@ class API::MembersController < API::ApiController
|
||||
def export_subscriptions
|
||||
authorize :export
|
||||
|
||||
export = Export.where(category:'users', export_type: 'subscriptions').where('created_at > ?', Subscription.maximum('updated_at')).last
|
||||
export = Export.where(category: 'users', export_type: 'subscriptions')
|
||||
.where('created_at > ?', Subscription.maximum('updated_at'))
|
||||
.last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new(category:'users', export_type: 'subscriptions', user: current_user)
|
||||
@export = Export.new(category: 'users', export_type: 'subscriptions', user: current_user)
|
||||
if @export.save
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
@ -111,7 +95,7 @@ class API::MembersController < API::ApiController
|
||||
def export_reservations
|
||||
authorize :export
|
||||
|
||||
export = Export.where(category:'users', export_type: 'reservations')
|
||||
export = Export.where(category: 'users', export_type: 'reservations')
|
||||
.where('created_at > ?', Reservation.maximum('updated_at'))
|
||||
.last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@ -131,11 +115,11 @@ class API::MembersController < API::ApiController
|
||||
def export_members
|
||||
authorize :export
|
||||
|
||||
export = Export.where(category:'users', export_type: 'members')
|
||||
export = Export.where(category: 'users', export_type: 'members')
|
||||
.where('created_at > ?', User.with_role(:member).maximum('updated_at'))
|
||||
.last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new(category:'users', export_type: 'members', user: current_user)
|
||||
@export = Export.new(category: 'users', export_type: 'members', user: current_user)
|
||||
if @export.save
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
@ -148,16 +132,15 @@ class API::MembersController < API::ApiController
|
||||
end
|
||||
end
|
||||
|
||||
# the user is querying to be mapped to his already existing account
|
||||
def merge
|
||||
authorize @member
|
||||
|
||||
# here the user query to be mapped to his already existing account
|
||||
|
||||
token = params.require(:user).permit(:auth_token)[:auth_token]
|
||||
token = token_param
|
||||
|
||||
@account = User.find_by(auth_token: token)
|
||||
if @account
|
||||
members_service = MembersService.new(@account)
|
||||
members_service = Members::MembersService.new(@account)
|
||||
begin
|
||||
if members_service.merge_from_sso(@member)
|
||||
@member = @account
|
||||
@ -168,7 +151,8 @@ class API::MembersController < API::ApiController
|
||||
render json: @member.errors, status: :unprocessable_entity
|
||||
end
|
||||
rescue DuplicateIndexError => error
|
||||
render json: { error: t('members.please_input_the_authentication_code_sent_to_the_address', EMAIL: error.message) }, status: :unprocessable_entity
|
||||
render json: { error: t('members.please_input_the_authentication_code_sent_to_the_address', EMAIL: error.message) },
|
||||
status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
render json: { error: t('members.your_authentication_code_is_not_valid') }, status: :unprocessable_entity
|
||||
@ -178,67 +162,17 @@ class API::MembersController < API::ApiController
|
||||
def list
|
||||
authorize User
|
||||
|
||||
p = params.require(:query).permit(:search, :order_by, :page, :size)
|
||||
render json: { error: 'page must be an integer' }, status: :unprocessable_entity and return unless query_params[:page].is_a? Integer
|
||||
render json: { error: 'size must be an integer' }, status: :unprocessable_entity and return unless query_params[:size].is_a? Integer
|
||||
|
||||
|
||||
render json: {error: 'page must be an integer'}, status: :unprocessable_entity unless p[:page].is_a? Integer
|
||||
|
||||
render json: {error: 'size must be an integer'}, status: :unprocessable_entity unless p[:size].is_a? Integer
|
||||
|
||||
|
||||
direction = (p[:order_by][0] == '-' ? 'DESC' : 'ASC')
|
||||
order_key = (p[:order_by][0] == '-' ? p[:order_by][1, p[:order_by].size] : p[:order_by])
|
||||
|
||||
order_key = case order_key
|
||||
when 'last_name'
|
||||
'profiles.last_name'
|
||||
when 'first_name'
|
||||
'profiles.first_name'
|
||||
when 'email'
|
||||
'users.email'
|
||||
when 'phone'
|
||||
'profiles.phone'
|
||||
when 'group'
|
||||
'groups.name'
|
||||
when 'plan'
|
||||
'plans.base_name'
|
||||
else
|
||||
'users.id'
|
||||
end
|
||||
|
||||
@query = User.includes(:profile, :group, :subscriptions)
|
||||
.joins(:profile, :group, :roles, 'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id" LEFT JOIN "plans" ON "plans"."id" = "subscriptions"."plan_id"')
|
||||
.where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
.order("#{order_key} #{direction}")
|
||||
.page(p[:page])
|
||||
.per(p[:size])
|
||||
|
||||
# ILIKE => PostgreSQL case-insensitive LIKE
|
||||
@query = @query.where('profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search OR profiles.phone ILIKE :search OR email ILIKE :search OR groups.name ILIKE :search OR plans.base_name ILIKE :search', search: "%#{p[:search]}%") if p[:search].size > 0
|
||||
|
||||
@members = @query.to_a
|
||||
query = Members::ListService.list(query_params)
|
||||
@max_members = query.except(:offset, :limit, :order).count
|
||||
@members = query.to_a
|
||||
|
||||
end
|
||||
|
||||
def search
|
||||
@members = User.includes(:profile)
|
||||
.joins(:profile, :roles, 'LEFT JOIN "subscriptions" ON "subscriptions"."user_id" = "users"."id"')
|
||||
.where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
.where("lower(f_unaccent(profiles.first_name)) ~ regexp_replace(:search, E'\\\\s+', '|') OR lower(f_unaccent(profiles.last_name)) ~ regexp_replace(:search, E'\\\\s+', '|')", search: params[:query].downcase)
|
||||
|
||||
if current_user.is_member?
|
||||
# non-admin can only retrieve users with "public profiles"
|
||||
@members = @members.where("users.is_allow_contact = 'true'")
|
||||
else
|
||||
# only admins have the ability to filter by subscription
|
||||
if params[:subscription] === 'true'
|
||||
@members = @members.where('subscriptions.id IS NOT NULL AND subscriptions.expired_at >= :now', now: Date.today.to_s)
|
||||
elsif params[:subscription] === 'false'
|
||||
@members = @members.where('subscriptions.id IS NULL OR subscriptions.expired_at < :now', now: Date.today.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
@members = @members.to_a
|
||||
@members = Members::ListService.search(current_user, params[:query], params[:subscription])
|
||||
end
|
||||
|
||||
def mapping
|
||||
@ -266,8 +200,8 @@ class API::MembersController < API::ApiController
|
||||
organization_attributes: [:id, :name,
|
||||
address_attributes: %i[id address]]])
|
||||
|
||||
elsif current_user.is_admin?
|
||||
params.require(:user).permit(:username, :email, :password, :password_confirmation, :invoicing_disabled,
|
||||
elsif current_user.admin?
|
||||
params.require(:user).permit(:username, :email, :password, :password_confirmation,
|
||||
:is_allow_contact, :is_allow_newsletter, :group_id,
|
||||
training_ids: [], tag_ids: [],
|
||||
profile_attributes: [:id, :first_name, :last_name, :gender, :birthday, :phone, :interest,
|
||||
@ -281,4 +215,12 @@ class API::MembersController < API::ApiController
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def token_param
|
||||
params.require(:user).permit(:auth_token)[:auth_token]
|
||||
end
|
||||
|
||||
def query_params
|
||||
params.require(:query).permit(:search, :order_by, :page, :size)
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Notification
|
||||
# Notifications are scoped by user
|
||||
class API::NotificationsController < API::ApiController
|
||||
include NotifyWith::NotificationsApi
|
||||
before_action :authenticate_user!
|
||||
@ -12,8 +16,8 @@ class API::NotificationsController < API::ApiController
|
||||
break unless delete_obsoletes(@notifications)
|
||||
end
|
||||
@totals = {
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
}
|
||||
render :index
|
||||
end
|
||||
@ -25,17 +29,19 @@ class API::NotificationsController < API::ApiController
|
||||
break unless delete_obsoletes(@notifications)
|
||||
end
|
||||
@totals = {
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
}
|
||||
render :index
|
||||
end
|
||||
|
||||
def polling
|
||||
@notifications = current_user.notifications.where('is_read = false AND created_at >= :date', date: params[:last_poll]).order('created_at DESC')
|
||||
@notifications = current_user.notifications
|
||||
.where('is_read = false AND created_at >= :date', date: params[:last_poll])
|
||||
.order('created_at DESC')
|
||||
@totals = {
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
total: current_user.notifications.count,
|
||||
unread: current_user.notifications.where(is_read: false).count
|
||||
}
|
||||
render :index
|
||||
end
|
||||
@ -45,7 +51,7 @@ class API::NotificationsController < API::ApiController
|
||||
def delete_obsoletes(notifications)
|
||||
cleaned = false
|
||||
notifications.each do |n|
|
||||
if !Module.const_get(n.attached_object_type) or !n.attached_object
|
||||
if !Module.const_get(n.attached_object_type) || !n.attached_object
|
||||
n.destroy!
|
||||
cleaned = true
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type OpenAPI::Client
|
||||
# OpenAPI::Clients are used to allow access to the public API
|
||||
class API::OpenAPIClientsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -5,7 +9,7 @@ class API::OpenAPIClientsController < API::ApiController
|
||||
authorize OpenAPI::Client
|
||||
@clients = OpenAPI::Client.order(:created_at)
|
||||
end
|
||||
# add authorization
|
||||
|
||||
def create
|
||||
@client = OpenAPI::Client.new(client_params)
|
||||
authorize @client
|
||||
@ -40,7 +44,8 @@ class API::OpenAPIClientsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def client_params
|
||||
params.require(:open_api_client).permit(:name)
|
||||
end
|
||||
|
||||
def client_params
|
||||
params.require(:open_api_client).permit(:name)
|
||||
end
|
||||
end
|
||||
|
@ -1,11 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Openlab::Projects
|
||||
# Openlab::Projects are Projects shared between different instances
|
||||
class API::OpenlabProjectsController < API::ApiController
|
||||
PROJECTS = Openlab::Projects.new
|
||||
|
||||
def index
|
||||
begin
|
||||
render json: PROJECTS.search(params[:q], page: params[:page], per_page: params[:per_page]).response.body
|
||||
rescue StandardError
|
||||
render json: { errors: ['service unavailable'] }
|
||||
end
|
||||
render json: PROJECTS.search(params[:q], page: params[:page], per_page: params[:per_page]).response.body
|
||||
rescue StandardError
|
||||
render json: { errors: ['service unavailable'] }
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,9 @@
|
||||
class API::PlansController < API::ApiController
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Plan and PartnerPlan.
|
||||
# Plan are used to define subscription's characteristics.
|
||||
# PartnerPlan is a special kind of plan which send notifications to an external user
|
||||
class API::PlansController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index]
|
||||
|
||||
def index
|
||||
@ -13,48 +18,19 @@
|
||||
|
||||
def create
|
||||
authorize Plan
|
||||
begin
|
||||
if plan_params[:type] and plan_params[:type] == 'PartnerPlan'
|
||||
|
||||
partner = User.find(params[:plan][:partner_id])
|
||||
unless %w[PartnerPlan Plan].include? plan_params[:type]
|
||||
render json: { error: 'unhandled plan type' }, status: :unprocessable_entity and return
|
||||
end
|
||||
|
||||
if plan_params[:group_id] == 'all'
|
||||
plans = PartnerPlan.create_for_all_groups(plan_params)
|
||||
if plans
|
||||
plans.each { |plan| partner.add_role :partner, plan }
|
||||
render json: { plan_ids: plans.map(&:id) }, status: :created
|
||||
else
|
||||
render status: :unprocessable_entity
|
||||
end
|
||||
type = plan_params[:type]
|
||||
partner = params[:plan][:partner_id].empty? ? nil : User.find(params[:plan][:partner_id])
|
||||
|
||||
else
|
||||
@plan = PartnerPlan.new(plan_params)
|
||||
if @plan.save
|
||||
partner.add_role :partner, @plan
|
||||
render :show, status: :created
|
||||
else
|
||||
render json: @plan.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
else
|
||||
if plan_params[:group_id] == 'all'
|
||||
plans = Plan.create_for_all_groups(plan_params)
|
||||
if plans
|
||||
render json: { plan_ids: plans.map(&:id) }, status: :created
|
||||
else
|
||||
render status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
@plan = Plan.new(plan_params)
|
||||
if @plan.save
|
||||
render :show, status: :created, location: @plan
|
||||
else
|
||||
render json: @plan.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Stripe::InvalidRequestError => e
|
||||
render json: {error: e.message}, status: :unprocessable_entity
|
||||
res = PlansService.create(type, partner, plan_params)
|
||||
if res[:errors]
|
||||
render res[:errors], status: :unprocessable_entity
|
||||
else
|
||||
render json: res, status: :created
|
||||
end
|
||||
end
|
||||
|
||||
@ -76,21 +52,25 @@
|
||||
end
|
||||
|
||||
private
|
||||
def plan_params
|
||||
if @parameters
|
||||
@parameters
|
||||
else
|
||||
@parameters = params
|
||||
@parameters[:plan][:amount] = @parameters[:plan][:amount].to_f * 100.0 if @parameters[:plan][:amount]
|
||||
|
||||
def plan_params
|
||||
# parameters caching for performance
|
||||
if @parameters
|
||||
@parameters
|
||||
else
|
||||
@parameters = params
|
||||
@parameters[:plan][:amount] = @parameters[:plan][:amount].to_f * 100.0 if @parameters[:plan][:amount]
|
||||
if @parameters[:plan][:prices_attributes]
|
||||
@parameters[:plan][:prices_attributes] = @parameters[:plan][:prices_attributes].map do |price|
|
||||
{ amount: price[:amount].to_f * 100.0, id: price[:id] }
|
||||
end if @parameters[:plan][:prices_attributes]
|
||||
|
||||
@parameters = @parameters.require(:plan).permit(:base_name, :type, :group_id, :amount, :interval, :interval_count, :is_rolling,
|
||||
:training_credit_nb, :ui_weight, :disabled,
|
||||
plan_file_attributes: [:id, :attachment, :_destroy],
|
||||
prices_attributes: [:id, :amount]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@parameters = @parameters.require(:plan)
|
||||
.permit(:base_name, :type, :group_id, :amount, :interval, :interval_count, :is_rolling,
|
||||
:training_credit_nb, :ui_weight, :disabled,
|
||||
plan_file_attributes: %i[id attachment _destroy],
|
||||
prices_attributes: %i[id amount])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type PriceCategory
|
||||
# PriceCategories are used in Events
|
||||
class API::PriceCategoriesController < API::ApiController
|
||||
before_action :authenticate_user!, only: [:update, :show, :create, :destroy]
|
||||
before_action :set_price_category, only: [:show, :update, :destroy]
|
||||
before_action :authenticate_user!, only: %i[update show create destroy]
|
||||
before_action :set_price_category, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
@price_categories = PriceCategory.all
|
||||
@ -15,8 +19,7 @@ class API::PriceCategoriesController < API::ApiController
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
def show; end
|
||||
|
||||
def create
|
||||
authorize PriceCategory
|
||||
@ -38,6 +41,7 @@ class API::PriceCategoriesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_price_category
|
||||
@price_category = PriceCategory.find(params[:id])
|
||||
end
|
||||
@ -45,4 +49,4 @@ class API::PriceCategoriesController < API::ApiController
|
||||
def price_category_params
|
||||
params.require(:price_category).permit(:name, :conditions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Price
|
||||
# Prices are used in reservations (Machine, Space)
|
||||
class API::PricesController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -6,29 +10,26 @@ class API::PricesController < API::ApiController
|
||||
@prices = Price.all
|
||||
if params[:priceable_type]
|
||||
@prices = @prices.where(priceable_type: params[:priceable_type])
|
||||
if params[:priceable_id]
|
||||
@prices = @prices.where(priceable_id: params[:priceable_id])
|
||||
end
|
||||
|
||||
@prices = @prices.where(priceable_id: params[:priceable_id]) if params[:priceable_id]
|
||||
end
|
||||
if params[:plan_id]
|
||||
if params[:plan_id] =~ /no|nil|null|undefined/i
|
||||
plan_id = nil
|
||||
else
|
||||
plan_id = params[:plan_id]
|
||||
end
|
||||
plan_id = if params[:plan_id] =~ /no|nil|null|undefined/i
|
||||
nil
|
||||
else
|
||||
params[:plan_id]
|
||||
end
|
||||
@prices = @prices.where(plan_id: plan_id)
|
||||
end
|
||||
if params[:group_id]
|
||||
@prices = @prices.where(group_id: params[:group_id])
|
||||
end
|
||||
@prices = @prices.where(group_id: params[:group_id]) if params[:group_id]
|
||||
end
|
||||
|
||||
def update
|
||||
authorize Price
|
||||
@price = Price.find(params[:id])
|
||||
_price_params = price_params
|
||||
_price_params[:amount] = _price_params[:amount] * 100
|
||||
if @price.update(_price_params)
|
||||
price_parameters = price_params
|
||||
price_parameters[:amount] = price_parameters[:amount] * 100
|
||||
if @price.update(price_parameters)
|
||||
render status: :ok
|
||||
else
|
||||
render status: :unprocessable_entity
|
||||
@ -36,15 +37,22 @@ class API::PricesController < API::ApiController
|
||||
end
|
||||
|
||||
def compute
|
||||
_price_params = compute_price_params
|
||||
price_parameters = compute_price_params
|
||||
# user
|
||||
_user = User.find(_price_params[:user_id])
|
||||
user = User.find(price_parameters[:user_id])
|
||||
# reservable
|
||||
if _price_params[:reservable_id].nil?
|
||||
if price_parameters[:reservable_id].nil?
|
||||
@amount = {elements: nil, total: 0, before_coupon: 0}
|
||||
else
|
||||
_reservable = _price_params[:reservable_type].constantize.find(_price_params[:reservable_id])
|
||||
@amount = Price.compute(current_user.is_admin?, _user, _reservable, _price_params[:slots_attributes] || [], _price_params[:plan_id], _price_params[:nb_reserve_places], _price_params[:tickets_attributes], coupon_params[:coupon_code])
|
||||
reservable = price_parameters[:reservable_type].constantize.find(price_parameters[:reservable_id])
|
||||
@amount = Price.compute(current_user.admin?,
|
||||
user,
|
||||
reservable,
|
||||
price_parameters[:slots_attributes] || [],
|
||||
price_parameters[:plan_id],
|
||||
price_parameters[:nb_reserve_places],
|
||||
price_parameters[:tickets_attributes],
|
||||
coupon_params[:coupon_code])
|
||||
end
|
||||
|
||||
|
||||
@ -56,14 +64,15 @@ class API::PricesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def price_params
|
||||
params.require(:price).permit(:amount)
|
||||
end
|
||||
|
||||
def compute_price_params
|
||||
params.require(:reservation).permit(:reservable_id, :reservable_type, :plan_id, :user_id, :nb_reserve_places,
|
||||
tickets_attributes: [:event_price_category_id, :booked],
|
||||
slots_attributes: [:id, :start_at, :end_at, :availability_id, :offered])
|
||||
tickets_attributes: %i[event_price_category_id booked],
|
||||
slots_attributes: %i[id start_at end_at availability_id offered])
|
||||
end
|
||||
|
||||
def coupon_params
|
||||
|
@ -1,5 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for managing Plans prices
|
||||
class API::PricingController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
|
||||
def index
|
||||
@group_pricing = Group.includes(:plans, :trainings_pricings)
|
||||
@ -10,14 +13,14 @@ class API::PricingController < API::ApiController
|
||||
if params[:training].present?
|
||||
training = Training.find params[:training]
|
||||
params[:group_pricing].each do |group_id, amount|
|
||||
if training
|
||||
group = Group.includes(:plans).find(group_id)
|
||||
if group
|
||||
training_pricing = group.trainings_pricings.find_or_initialize_by(training_id: training.id)
|
||||
training_pricing.amount = amount * 100
|
||||
training_pricing.save
|
||||
end
|
||||
end
|
||||
next unless training
|
||||
|
||||
group = Group.includes(:plans).find(group_id)
|
||||
next unless group
|
||||
|
||||
training_pricing = group.trainings_pricings.find_or_initialize_by(training_id: training.id)
|
||||
training_pricing.amount = amount * 100
|
||||
training_pricing.save
|
||||
end
|
||||
end
|
||||
head 200
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Project
|
||||
class API::ProjectsController < API::ApiController
|
||||
before_action :authenticate_user!, except: %i[index show last_published search]
|
||||
before_action :set_project, only: %i[update destroy]
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Reservation
|
||||
# Reservations are used for Training, Machine, Space and Event
|
||||
class API::ReservationsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_reservation, only: %i[show update]
|
||||
@ -5,10 +9,10 @@ class API::ReservationsController < API::ApiController
|
||||
|
||||
def index
|
||||
if params[:reservable_id] && params[:reservable_type] && params[:user_id]
|
||||
params[:user_id] = current_user.id unless current_user.is_admin?
|
||||
params[:user_id] = current_user.id unless current_user.admin?
|
||||
|
||||
@reservations = Reservation.where(params.permit(:reservable_id, :reservable_type, :user_id))
|
||||
elsif params[:reservable_id] && params[:reservable_type] && current_user.is_admin?
|
||||
elsif params[:reservable_id] && params[:reservable_type] && current_user.admin?
|
||||
@reservations = Reservation.where(params.permit(:reservable_id, :reservable_type))
|
||||
else
|
||||
@reservations = []
|
||||
@ -18,8 +22,8 @@ class API::ReservationsController < API::ApiController
|
||||
def show; end
|
||||
|
||||
def create
|
||||
method = current_user.is_admin? ? :local : :stripe
|
||||
user_id = current_user.is_admin? ? reservation_params[:user_id] : current_user.id
|
||||
method = current_user.admin? ? :local : :stripe
|
||||
user_id = current_user.admin? ? reservation_params[:user_id] : current_user.id
|
||||
|
||||
@reservation = Reservation.new(reservation_params)
|
||||
is_reserve = Reservations::Reserve.new(user_id)
|
||||
@ -46,6 +50,7 @@ class API::ReservationsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_reservation
|
||||
@reservation = Reservation.find(params[:id])
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Setting
|
||||
class API::SettingsController < API::ApiController
|
||||
before_action :authenticate_user!, only: :update
|
||||
|
||||
@ -17,6 +20,7 @@ class API::SettingsController < API::ApiController
|
||||
|
||||
def show
|
||||
@setting = Setting.find_or_create_by(name: params[:name])
|
||||
@show_history = params[:history] == 'true' && current_user.admin?
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -1,6 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Slot
|
||||
# Slots are used to cut Availabilities into reservable slots of ApplicationHelper::SLOT_DURATION minutes
|
||||
class API::SlotsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_slot, only: [:update, :cancel]
|
||||
before_action :set_slot, only: %i[update cancel]
|
||||
respond_to :json
|
||||
|
||||
def update
|
||||
@ -15,10 +19,11 @@ class API::SlotsController < API::ApiController
|
||||
|
||||
def cancel
|
||||
authorize @slot
|
||||
@slot.update_attributes(:canceled_at => DateTime.now)
|
||||
@slot.update_attributes(canceled_at: DateTime.now)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_slot
|
||||
@slot = Slot.find(params[:id])
|
||||
end
|
||||
|
@ -1,5 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Space
|
||||
class API::SpacesController < API::ApiController
|
||||
before_action :authenticate_user!, except: [:index, :show]
|
||||
before_action :authenticate_user!, except: %i[index show]
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@ -38,12 +41,14 @@ class API::SpacesController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
def get_space
|
||||
Space.friendly.find(params[:id])
|
||||
end
|
||||
|
||||
def space_params
|
||||
params.require(:space).permit(:name, :description, :characteristics, :default_places, :disabled, space_image_attributes: [:attachment],
|
||||
space_files_attributes: [:id, :attachment, :_destroy])
|
||||
end
|
||||
def get_space
|
||||
Space.friendly.find(params[:id])
|
||||
end
|
||||
|
||||
def space_params
|
||||
params.require(:space).permit(:name, :description, :characteristics, :default_places, :disabled,
|
||||
space_image_attributes: [:attachment],
|
||||
space_files_attributes: %i[id attachment _destroy])
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Space
|
||||
class API::StatisticsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -6,7 +9,7 @@ class API::StatisticsController < API::ApiController
|
||||
@statistics = StatisticIndex.all
|
||||
end
|
||||
|
||||
%w(account event machine project subscription training user space).each do |path|
|
||||
%w[account event machine project subscription training user space].each do |path|
|
||||
class_eval %{
|
||||
def #{path}
|
||||
authorize :statistic, :#{path}?
|
||||
@ -27,38 +30,50 @@ class API::StatisticsController < API::ApiController
|
||||
# return result
|
||||
render json: results
|
||||
end
|
||||
}, __FILE__, __LINE__ - 20
|
||||
end
|
||||
|
||||
%w[account event machine project subscription training user space].each do |path|
|
||||
class_eval %{
|
||||
def export_#{path}
|
||||
authorize :statistic, :export_#{path}?
|
||||
|
||||
export = Export.where({category:'statistics', export_type: '#{path}', query: params[:body], key: params[:type_key]}).last
|
||||
export = Export.where(category:'statistics', export_type: '#{path}', query: params[:body], key: params[:type_key]).last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new({category:'statistics', export_type: '#{path}', user: current_user, query: params[:body], key: params[:type_key]})
|
||||
@export = Export.new(category:'statistics',
|
||||
export_type: '#{path}',
|
||||
user: current_user,
|
||||
query: params[:body],
|
||||
key: params[:type_key])
|
||||
if @export.save
|
||||
render json: {export_id: @export.id}, status: :ok
|
||||
else
|
||||
render json: @export.errors, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
send_file File.join(Rails.root, export.file), :type => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :disposition => 'attachment'
|
||||
send_file File.join(Rails.root, export.file),
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
disposition: 'attachment'
|
||||
end
|
||||
end
|
||||
}
|
||||
}, __FILE__, __LINE__ - 22
|
||||
end
|
||||
|
||||
def export_global
|
||||
authorize :statistic, :export_global?
|
||||
|
||||
export = Export.where({category:'statistics', export_type: 'global', query: params[:body]}).last
|
||||
export = Export.where(category: 'statistics', export_type: 'global', query: params[:body]).last
|
||||
if export.nil? || !FileTest.exist?(export.file)
|
||||
@export = Export.new({category:'statistics', export_type: 'global', user: current_user, query: params[:body]})
|
||||
@export = Export.new(category: 'statistics', export_type: 'global', user: current_user, query: params[:body])
|
||||
if @export.save
|
||||
render json: {export_id: @export.id}, status: :ok
|
||||
render json: { export_id: @export.id }, status: :ok
|
||||
else
|
||||
render json: @export.errors, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
send_file File.join(Rails.root, export.file), :type => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :disposition => 'attachment'
|
||||
send_file File.join(Rails.root, export.file),
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
disposition: 'attachment'
|
||||
end
|
||||
end
|
||||
|
||||
@ -68,5 +83,4 @@ class API::StatisticsController < API::ApiController
|
||||
results = Elasticsearch::Model.client.scroll scroll: params[:scroll], scroll_id: params[:scrollId]
|
||||
render json: results
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,3 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Stylesheet
|
||||
# Stylesheets are used to customize the appearance of fab-manager
|
||||
class API::StylesheetsController < API::ApiController
|
||||
caches_page :show # magic happens here
|
||||
|
||||
@ -5,7 +9,7 @@ class API::StylesheetsController < API::ApiController
|
||||
@stylesheet = Stylesheet.find(params[:id])
|
||||
respond_to do |format|
|
||||
format.html # regular ERB template
|
||||
format.css { render :text => @stylesheet.contents, :content_type => 'text/css' }
|
||||
format.css { render text: @stylesheet.contents, content_type: 'text/css' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Subscription
|
||||
class API::SubscriptionsController < API::ApiController
|
||||
include FablabConfiguration
|
||||
|
||||
@ -12,8 +15,8 @@ class API::SubscriptionsController < API::ApiController
|
||||
if fablab_plans_deactivated?
|
||||
head 403
|
||||
else
|
||||
method = current_user.is_admin? ? :local : :stripe
|
||||
user_id = current_user.is_admin? ? subscription_params[:user_id] : current_user.id
|
||||
method = current_user.admin? ? :local : :stripe
|
||||
user_id = current_user.admin? ? subscription_params[:user_id] : current_user.id
|
||||
|
||||
@subscription = Subscription.new(subscription_params)
|
||||
is_subscribe = Subscriptions::Subscribe.new(user_id)
|
||||
@ -64,7 +67,7 @@ class API::SubscriptionsController < API::ApiController
|
||||
params.require(:subscription).permit(:expired_at)
|
||||
end
|
||||
|
||||
# TODO refactor subscriptions logic and move this in model/validator
|
||||
# TODO, refactor subscriptions logic and move this in model/validator
|
||||
def valid_card_token?(token)
|
||||
Stripe::Token.retrieve(token)
|
||||
rescue Stripe::InvalidRequestError => e
|
||||
|
@ -1,15 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Tag
|
||||
# Tags are used to restrict access to Availabilities
|
||||
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
|
||||
@ -37,6 +39,7 @@ class API::TagsController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_tag
|
||||
@tag = Tag.find(params[:id])
|
||||
end
|
||||
@ -44,4 +47,4 @@ class API::TagsController < API::ApiController
|
||||
def tag_params
|
||||
params.require(:tag).permit(:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Theme
|
||||
# Themes are used in Projects
|
||||
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 +38,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,19 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Training
|
||||
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]
|
||||
@trainings = policy_scope(Training)
|
||||
if params[:public_page]
|
||||
@trainings = @trainings.where(public_page: true)
|
||||
end
|
||||
@trainings = @trainings.where(public_page: true) if params[:public_page]
|
||||
|
||||
if attribute_requested?(@requested_attributes, 'availabilities')
|
||||
@trainings = @trainings.includes(:availabilities => [:slots => [:reservation => [:user => [:profile, :trainings]]]]).order('availabilities.start_at DESC')
|
||||
end
|
||||
return unless attribute_requested?(@requested_attributes, 'availabilities')
|
||||
|
||||
@trainings = @trainings.includes(availabilities: [slots: [reservation: [user: %i[profile trainings]]]])
|
||||
.order('availabilities.start_at DESC')
|
||||
end
|
||||
|
||||
def show
|
||||
@ -39,12 +41,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 +57,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
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for managing Training prices
|
||||
class API::TrainingsPricingsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -6,11 +9,11 @@ class API::TrainingsPricingsController < API::ApiController
|
||||
end
|
||||
|
||||
def update
|
||||
if current_user.is_admin?
|
||||
if current_user.admin?
|
||||
@trainings_pricing = TrainingsPricing.find(params[:id])
|
||||
_trainings_pricing_params = trainings_pricing_params
|
||||
_trainings_pricing_params[:amount] = _trainings_pricing_params[:amount] * 100
|
||||
if @trainings_pricing.update(_trainings_pricing_params)
|
||||
trainings_pricing_parameters = trainings_pricing_params
|
||||
trainings_pricing_parameters[:amount] = trainings_pricing_parameters[:amount] * 100
|
||||
if @trainings_pricing.update(trainings_pricing_parameters)
|
||||
render status: :ok
|
||||
else
|
||||
render status: :unprocessable_entity
|
||||
|
@ -1,11 +1,14 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for managing front-end translations
|
||||
class API::TranslationsController < API::ApiController
|
||||
before_action :set_locale
|
||||
|
||||
|
||||
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 +18,4 @@ class API::TranslationsController < API::ApiController
|
||||
I18n.locale = params[:locale] || I18n.default_locale
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,8 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Users with role :partner
|
||||
class API::UsersController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
def index
|
||||
if current_user.is_admin? and params[:role] == 'partner'
|
||||
if current_user.admin? && params[:role] == 'partner'
|
||||
@users = User.with_role(:partner).includes(:profile)
|
||||
else
|
||||
head 403
|
||||
@ -10,11 +13,18 @@ class API::UsersController < API::ApiController
|
||||
end
|
||||
|
||||
def create
|
||||
if current_user.is_admin?
|
||||
if current_user.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 +39,7 @@ class API::UsersController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def partner_params
|
||||
params.require(:user).permit(:email, :first_name, :last_name)
|
||||
end
|
||||
|
@ -1,4 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller to get the fab-manager version
|
||||
class API::VersionController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for resources of type Wallet
|
||||
class API::WalletController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
|
||||
@ -19,9 +22,7 @@ class API::WalletController < API::ApiController
|
||||
service = WalletService.new(user: current_user, wallet: @wallet)
|
||||
transaction = service.credit(credit_params[:amount].to_f)
|
||||
if transaction
|
||||
if credit_params[:avoir]
|
||||
service.create_avoir(transaction, credit_params[:avoir_date], credit_params[:avoir_description])
|
||||
end
|
||||
service.create_avoir(transaction, credit_params[:avoir_date], credit_params[:avoir_description]) if credit_params[:avoir]
|
||||
render :show
|
||||
else
|
||||
head 422
|
||||
@ -29,6 +30,7 @@ class API::WalletController < API::ApiController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def credit_params
|
||||
params.permit(:id, :amount, :avoir, :avoir_date, :avoir_description)
|
||||
end
|
||||
|
@ -1,3 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Main controller for the backend application. All controllers inherits from it
|
||||
class ApplicationController < ActionController::Base
|
||||
include Pundit
|
||||
# Prevent CSRF attacks by raising an exception.
|
||||
@ -14,10 +17,10 @@ class ApplicationController < ActionController::Base
|
||||
# Returning 403 Forbidden if permission is denied
|
||||
rescue_from Pundit::NotAuthorizedError, with: :permission_denied
|
||||
|
||||
def index
|
||||
end
|
||||
def index; end
|
||||
|
||||
protected
|
||||
|
||||
def set_csrf_cookie
|
||||
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
|
||||
end
|
||||
@ -28,17 +31,29 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
def configure_permitted_parameters
|
||||
devise_parameter_sanitizer.for(:sign_up) <<
|
||||
{profile_attributes: [:phone, :last_name, :first_name,
|
||||
:gender, :birthday, :interest, :software_mastered,
|
||||
organization_attributes: [:name, address_attributes: [:address]]]}
|
||||
devise_parameter_sanitizer.for(:sign_up).concat [:username, :is_allow_contact, :is_allow_newsletter, :cgu, :group_id]
|
||||
{ profile_attributes: [:phone, :last_name, :first_name, :gender, :birthday, :interest, :software_mastered,
|
||||
organization_attributes: [:name, address_attributes: [:address]]] }
|
||||
|
||||
devise_parameter_sanitizer.for(:sign_up).concat %i[username is_allow_contact is_allow_newsletter cgu group_id]
|
||||
end
|
||||
|
||||
def default_url_options
|
||||
{ :host => Rails.application.secrets.default_host, protocol: Rails.application.secrets.default_protocol }
|
||||
{ host: Rails.application.secrets.default_host, protocol: Rails.application.secrets.default_protocol }
|
||||
end
|
||||
|
||||
def permission_denied
|
||||
head 403
|
||||
end
|
||||
|
||||
# @return [User]
|
||||
# This is a placeholder for Devise's current_user.
|
||||
# As Devise generate the method at runtime, IDEs autocomplete features will complain about 'method not found'
|
||||
def current_user
|
||||
super
|
||||
end
|
||||
|
||||
# This is a placeholder for Devise's authenticate_user! method.
|
||||
def authenticate_user!
|
||||
super
|
||||
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,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Coupon is a textual code associated with a discount rate or an amount of discount
|
||||
class Coupon < ActiveRecord::Base
|
||||
has_many :invoices
|
||||
|
||||
@ -6,7 +9,7 @@ class Coupon < ActiveRecord::Base
|
||||
|
||||
validates :name, presence: true
|
||||
validates :code, presence: true
|
||||
validates :code, format: { with: /\A[A-Z0-9\-]+\z/, message: 'only caps letters, numbers, and dashes'}
|
||||
validates :code, format: { with: /\A[A-Z0-9\-]+\z/, message: 'only caps letters, numbers, and dashes' }
|
||||
validates :code, uniqueness: true
|
||||
validates :validity_per_user, presence: true
|
||||
validates :validity_per_user, inclusion: { in: %w[once forever] }
|
||||
@ -52,9 +55,9 @@ class Coupon < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def type
|
||||
if amount_off.nil? and !percent_off.nil?
|
||||
if amount_off.nil? && !percent_off.nil?
|
||||
'percent_off'
|
||||
elsif percent_off.nil? and !amount_off.nil?
|
||||
elsif percent_off.nil? && !amount_off.nil?
|
||||
'amount_off'
|
||||
end
|
||||
end
|
||||
|
@ -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,20 @@ 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?
|
||||
|
||||
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 +63,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 +84,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 +104,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 +144,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 +169,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 +180,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 +197,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 +206,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 +237,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
|
||||
|
@ -43,4 +43,5 @@ class NotificationType
|
||||
notify_member_about_coupon
|
||||
notify_member_reservation_reminder
|
||||
]
|
||||
# deprecated: notify_admin_invoicing_changed
|
||||
end
|
||||
|
@ -27,8 +27,8 @@ class Plan < ActiveRecord::Base
|
||||
|
||||
validates :amount, :group, :base_name, presence: true
|
||||
validates :interval_count, numericality: { only_integer: true, greater_than_or_equal_to: 1 }
|
||||
validates :interval_count, numericality: { less_than: 12 }, if: proc { |plan| plan.interval == 'month' }
|
||||
validates :interval_count, numericality: { less_than: 52 }, if: proc { |plan| plan.interval == 'week' }
|
||||
validates :interval_count, numericality: { less_than: 13 }, if: proc { |plan| plan.interval == 'month' }
|
||||
validates :interval_count, numericality: { less_than: 53 }, if: proc { |plan| plan.interval == 'week' }
|
||||
validates :interval, inclusion: { in: %w[year month week] }
|
||||
validates :base_name, :slug, presence: true
|
||||
|
||||
|
@ -190,7 +190,7 @@ class Reservation < ActiveRecord::Base
|
||||
@coupon = Coupon.find_by(code: coupon_code)
|
||||
raise InvalidCouponError if @coupon.nil? || @coupon.status(user.id) != 'active'
|
||||
|
||||
total = get_cart_total
|
||||
total = cart_total
|
||||
|
||||
discount = if @coupon.type == 'percent_off'
|
||||
(total * @coupon.percent_off / 100).to_i
|
||||
@ -210,7 +210,7 @@ class Reservation < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
@wallet_amount_debit = get_wallet_amount_debit
|
||||
@wallet_amount_debit = wallet_amount_debit
|
||||
if @wallet_amount_debit != 0 && !on_site
|
||||
invoice_items << Stripe::InvoiceItem.create(
|
||||
customer: user.stp_customer_id,
|
||||
@ -261,9 +261,8 @@ class Reservation < ActiveRecord::Base
|
||||
# error handling
|
||||
invoice_items.each(&:delete)
|
||||
errors[:card] << subscription.errors[:card].join
|
||||
if subscription.errors[:payment]
|
||||
errors[:payment] << subscription.errors[:payment].join
|
||||
end
|
||||
|
||||
errors[:payment] << subscription.errors[:payment].join if subscription.errors[:payment]
|
||||
return false
|
||||
end
|
||||
|
||||
@ -347,50 +346,31 @@ class Reservation < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def clear_payment_info(card, invoice)
|
||||
begin
|
||||
card.delete if card
|
||||
if invoice
|
||||
invoice.closed = true
|
||||
invoice.save
|
||||
end
|
||||
rescue Stripe::InvalidRequestError => e
|
||||
logger.error e
|
||||
rescue Stripe::AuthenticationError => e
|
||||
logger.error e
|
||||
rescue Stripe::APIConnectionError => e
|
||||
logger.error e
|
||||
rescue Stripe::StripeError => e
|
||||
logger.error e
|
||||
rescue => e
|
||||
logger.error e
|
||||
card&.delete
|
||||
if invoice
|
||||
invoice.closed = true
|
||||
invoice.save
|
||||
end
|
||||
rescue Stripe::InvalidRequestError => e
|
||||
logger.error e
|
||||
rescue Stripe::AuthenticationError => e
|
||||
logger.error e
|
||||
rescue Stripe::APIConnectionError => e
|
||||
logger.error e
|
||||
rescue Stripe::StripeError => e
|
||||
logger.error e
|
||||
rescue StandardError => e
|
||||
logger.error e
|
||||
end
|
||||
|
||||
def clean_pending_strip_invoice_items
|
||||
pending_invoice_items = Stripe::InvoiceItem.list(customer: user.stp_customer_id, limit: 100).data.select { |ii| ii.invoice.nil? }
|
||||
pending_invoice_items.each do |ii|
|
||||
ii.delete
|
||||
end
|
||||
pending_invoice_items.each(&:delete)
|
||||
end
|
||||
|
||||
def save_with_local_payment(coupon_code = nil)
|
||||
if user.invoicing_disabled?
|
||||
if valid?
|
||||
### generate invoice only for calcul price, TODO refactor!!
|
||||
build_invoice(user: user)
|
||||
generate_invoice_items(true, coupon_code)
|
||||
@wallet_amount_debit = get_wallet_amount_debit
|
||||
self.invoice = nil
|
||||
###
|
||||
|
||||
save!
|
||||
UsersCredits::Manager.new(reservation: self).update_credits
|
||||
return true
|
||||
end
|
||||
else
|
||||
build_invoice(user: user)
|
||||
generate_invoice_items(true, coupon_code)
|
||||
end
|
||||
build_invoice(user: user)
|
||||
generate_invoice_items(true, coupon_code)
|
||||
|
||||
return false unless valid?
|
||||
|
||||
@ -420,38 +400,38 @@ class Reservation < ActiveRecord::Base
|
||||
|
||||
def total_booked_seats
|
||||
total = nb_reserve_places
|
||||
if tickets.count > 0
|
||||
total += tickets.map(&:booked).map(&:to_i).reduce(:+)
|
||||
end
|
||||
total += tickets.map(&:booked).map(&:to_i).reduce(:+) if tickets.count.positive?
|
||||
|
||||
total
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def machine_not_already_reserved
|
||||
already_reserved = false
|
||||
self.slots.each do |slot|
|
||||
slots.each do |slot|
|
||||
same_hour_slots = Slot.joins(:reservations).where(
|
||||
reservations: { reservable_type: self.reservable_type,
|
||||
reservable_id: self.reservable_id
|
||||
},
|
||||
start_at: slot.start_at,
|
||||
end_at: slot.end_at,
|
||||
availability_id: slot.availability_id,
|
||||
canceled_at: nil)
|
||||
reservations: { reservable_type: reservable_type, reservable_id: reservable_id },
|
||||
start_at: slot.start_at,
|
||||
end_at: slot.end_at,
|
||||
availability_id: slot.availability_id,
|
||||
canceled_at: nil
|
||||
)
|
||||
if same_hour_slots.any?
|
||||
already_reserved = true
|
||||
break
|
||||
end
|
||||
end
|
||||
errors.add(:machine, "already reserved") if already_reserved
|
||||
errors.add(:machine, 'already reserved') if already_reserved
|
||||
end
|
||||
|
||||
def training_not_fully_reserved
|
||||
slot = self.slots.first
|
||||
errors.add(:training, "already fully reserved") if Availability.find(slot.availability_id).completed?
|
||||
slot = slots.first
|
||||
errors.add(:training, 'already fully reserved') if Availability.find(slot.availability_id).completed?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def notify_member_create_reservation
|
||||
NotificationCenter.call type: 'notify_member_create_reservation',
|
||||
receiver: user,
|
||||
@ -480,8 +460,8 @@ class Reservation < ActiveRecord::Base
|
||||
reservable.update_columns(nb_free_places: nb_free_places)
|
||||
end
|
||||
|
||||
def get_cart_total
|
||||
total = (self.invoice.invoice_items.map(&:amount).map(&:to_i).reduce(:+) or 0)
|
||||
def cart_total
|
||||
total = (invoice.invoice_items.map(&:amount).map(&:to_i).reduce(:+) or 0)
|
||||
if plan_id.present?
|
||||
plan = Plan.find(plan_id)
|
||||
total += plan.amount
|
||||
@ -489,30 +469,24 @@ class Reservation < ActiveRecord::Base
|
||||
total
|
||||
end
|
||||
|
||||
def get_wallet_amount_debit
|
||||
total = get_cart_total
|
||||
if @coupon
|
||||
total = CouponService.new.apply(total, @coupon, user.id)
|
||||
end
|
||||
def wallet_amount_debit
|
||||
total = cart_total
|
||||
total = CouponService.new.apply(total, @coupon, user.id) if @coupon
|
||||
|
||||
wallet_amount = (user.wallet.amount * 100).to_i
|
||||
|
||||
wallet_amount >= total ? total : wallet_amount
|
||||
end
|
||||
|
||||
def debit_user_wallet
|
||||
if @wallet_amount_debit.present? and @wallet_amount_debit != 0
|
||||
amount = @wallet_amount_debit / 100.0
|
||||
wallet_transaction = WalletService.new(user: user, wallet: user.wallet).debit(amount, self)
|
||||
# wallet debit success
|
||||
if wallet_transaction
|
||||
# payment by online or (payment by local and invoice isnt disabled)
|
||||
if stp_invoice_id or !user.invoicing_disabled?
|
||||
self.invoice.update_columns(wallet_amount: @wallet_amount_debit, wallet_transaction_id: wallet_transaction.id)
|
||||
end
|
||||
else
|
||||
raise DebitWalletError
|
||||
end
|
||||
end
|
||||
return unless @wallet_amount_debit.present? && @wallet_amount_debit != 0
|
||||
|
||||
amount = @wallet_amount_debit / 100.0
|
||||
wallet_transaction = WalletService.new(user: user, wallet: user.wallet).debit(amount, self)
|
||||
# wallet debit success
|
||||
raise DebitWalletError unless wallet_transaction
|
||||
|
||||
invoice.update_columns(wallet_amount: @wallet_amount_debit, wallet_transaction_id: wallet_transaction.id)
|
||||
end
|
||||
|
||||
# this function only use for compute total of reservation before save
|
||||
@ -520,13 +494,11 @@ class Reservation < ActiveRecord::Base
|
||||
total = invoice.invoice_items.map(&:amount).map(&:to_i).reduce(:+)
|
||||
unless coupon_code.nil?
|
||||
cp = Coupon.find_by(code: coupon_code)
|
||||
if not cp.nil? and cp.status(user.id) == 'active'
|
||||
total = CouponService.new.apply(total, cp, user.id)
|
||||
else
|
||||
raise InvalidCouponError
|
||||
end
|
||||
raise InvalidCouponError unless !cp.nil? && cp.status(user.id) == 'active'
|
||||
|
||||
total = CouponService.new.apply(total, cp, user.id)
|
||||
end
|
||||
return total - get_wallet_amount_debit
|
||||
total - wallet_amount_debit
|
||||
end
|
||||
|
||||
##
|
||||
@ -539,14 +511,12 @@ class Reservation < ActiveRecord::Base
|
||||
|
||||
unless coupon_code.nil?
|
||||
cp = Coupon.find_by(code: coupon_code)
|
||||
if not cp.nil? and cp.status(user.id) == 'active'
|
||||
total = CouponService.new.apply(total, cp, user.id)
|
||||
self.invoice.coupon_id = cp.id
|
||||
else
|
||||
raise InvalidCouponError
|
||||
end
|
||||
raise InvalidCouponError unless !cp.nil? && cp.status(user.id) == 'active'
|
||||
|
||||
total = CouponService.new.apply(total, cp, user.id)
|
||||
invoice.coupon_id = cp.id
|
||||
end
|
||||
|
||||
self.invoice.total = total
|
||||
invoice.total = total
|
||||
end
|
||||
end
|
||||
|
@ -142,14 +142,12 @@ class Subscription < ActiveRecord::Base
|
||||
# debit wallet
|
||||
wallet_transaction = debit_user_wallet
|
||||
|
||||
unless user.invoicing_disabled?
|
||||
invoc = generate_invoice(nil, coupon_code)
|
||||
if wallet_transaction
|
||||
invoc.wallet_amount = @wallet_amount_debit
|
||||
invoc.wallet_transaction_id = wallet_transaction.id
|
||||
end
|
||||
invoc.save
|
||||
invoc = generate_invoice(nil, coupon_code)
|
||||
if wallet_transaction
|
||||
invoc.wallet_amount = @wallet_amount_debit
|
||||
invoc.wallet_transaction_id = wallet_transaction.id
|
||||
end
|
||||
invoc.save
|
||||
end
|
||||
true
|
||||
end
|
||||
|
@ -1,8 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# User is a physical or moral person with its authentication parameters
|
||||
# It is linked to the Profile model with hold informations about this person (like address, name, etc.)
|
||||
class User < ActiveRecord::Base
|
||||
include NotifyWith::NotificationReceiver
|
||||
include NotifyWith::NotificationAttachedObject
|
||||
# Include default devise modules. Others available are:
|
||||
# :confirmable, :lockable, :timeoutable and :omniauthable
|
||||
# :lockable, :timeoutable and :omniauthable
|
||||
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable,
|
||||
:confirmable, :async
|
||||
rolify
|
||||
@ -50,6 +54,8 @@ class User < ActiveRecord::Base
|
||||
|
||||
has_many :exports, dependent: :destroy
|
||||
|
||||
has_many :history_values, dependent: :nullify
|
||||
|
||||
# fix for create admin user
|
||||
before_save do
|
||||
email&.downcase!
|
||||
@ -59,7 +65,6 @@ class User < ActiveRecord::Base
|
||||
after_create :create_a_wallet
|
||||
after_commit :create_stripe_customer, on: [:create]
|
||||
after_commit :notify_admin_when_user_is_created, on: :create
|
||||
after_update :notify_admin_invoicing_changed, if: :invoicing_disabled_changed?
|
||||
after_update :notify_group_changed, if: :group_id_changed?
|
||||
|
||||
attr_accessor :cgu
|
||||
@ -74,7 +79,7 @@ class User < ActiveRecord::Base
|
||||
scope :without_subscription, -> { includes(:subscriptions).where(subscriptions: { user_id: nil }) }
|
||||
scope :with_subscription, -> { joins(:subscriptions) }
|
||||
|
||||
def to_json(options = {})
|
||||
def to_json(*)
|
||||
ApplicationController.new.view_context.render(
|
||||
partial: 'api/members/member',
|
||||
locals: { member: self },
|
||||
@ -88,7 +93,7 @@ class User < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def training_machine?(machine)
|
||||
return true if is_admin?
|
||||
return true if admin?
|
||||
|
||||
trainings.map(&:machines).flatten.uniq.include?(machine)
|
||||
end
|
||||
@ -107,11 +112,11 @@ class User < ActiveRecord::Base
|
||||
subscriptions.order(:created_at).last
|
||||
end
|
||||
|
||||
def is_admin?
|
||||
def admin?
|
||||
has_role? :admin
|
||||
end
|
||||
|
||||
def is_member?
|
||||
def member?
|
||||
has_role? :member
|
||||
end
|
||||
|
||||
@ -122,7 +127,7 @@ class User < ActiveRecord::Base
|
||||
def generate_subscription_invoice
|
||||
return unless subscription
|
||||
|
||||
subscription.generate_and_save_invoice unless invoicing_disabled?
|
||||
subscription.generate_and_save_invoice
|
||||
end
|
||||
|
||||
def stripe_customer
|
||||
@ -286,7 +291,6 @@ class User < ActiveRecord::Base
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def assign_default_role
|
||||
@ -341,12 +345,4 @@ class User < ActiveRecord::Base
|
||||
receiver: self,
|
||||
attached_object: self
|
||||
end
|
||||
|
||||
def notify_admin_invoicing_changed
|
||||
NotificationCenter.call type: 'notify_admin_invoicing_changed',
|
||||
receiver: User.admins,
|
||||
attached_object: self
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
@ -1,9 +1,9 @@
|
||||
class AdminPolicy < ApplicationPolicy
|
||||
def index?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
class AgeRangePolicy < ApplicationPolicy
|
||||
%w(create update destroy show).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -8,7 +8,7 @@ class AuthProviderPolicy < ApplicationPolicy
|
||||
|
||||
%w(index? show? create? update? destroy? mapping_fields?).each do |action|
|
||||
define_method action do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
class AvailabilityPolicy < ApplicationPolicy
|
||||
%w(index? show? create? update? destroy? reservations? export? lock?).each do |action|
|
||||
define_method action do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
class CategoryPolicy < ApplicationPolicy
|
||||
%w(create update destroy show).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,6 @@
|
||||
class ComponentPolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
|
@ -1,7 +1,7 @@
|
||||
class CouponPolicy < ApplicationPolicy
|
||||
%w(index show create update destroy send_to).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,6 @@
|
||||
class CreditPolicy < ApplicationPolicy
|
||||
def index?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def create?
|
||||
|
@ -1,11 +1,11 @@
|
||||
class CustomAssetPolicy < ApplicationPolicy
|
||||
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
class EventPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
if user.nil? or (user and !user.is_admin?)
|
||||
if user.nil? or (user and !user.admin?)
|
||||
scope.includes(:event_image, :event_files, :availability, :category)
|
||||
.where('availabilities.start_at >= ?', Time.now)
|
||||
.order('availabilities.start_at ASC')
|
||||
@ -14,7 +14,7 @@ class EventPolicy < ApplicationPolicy
|
||||
end
|
||||
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
|
@ -1,7 +1,7 @@
|
||||
class EventThemePolicy < ApplicationPolicy
|
||||
%w(create update destroy show).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
class ExportPolicy < Struct.new(:user, :export)
|
||||
%w(export_reservations export_members export_subscriptions export_availabilities download status).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,13 @@
|
||||
class GroupPolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.is_admin? and record.destroyable?
|
||||
user.admin? and record.destroyable?
|
||||
end
|
||||
end
|
||||
|
@ -1,17 +1,17 @@
|
||||
class InvoicePolicy < ApplicationPolicy
|
||||
def index?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def download?
|
||||
user.is_admin? or (record.user_id == user.id)
|
||||
user.admin? or (record.user_id == user.id)
|
||||
end
|
||||
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def list?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,6 @@
|
||||
class LicencePolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
|
@ -1,13 +1,13 @@
|
||||
class MachinePolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.is_admin? and record.destroyable?
|
||||
user.admin? and record.destroyable?
|
||||
end
|
||||
end
|
||||
|
@ -1,17 +1,17 @@
|
||||
class PartnerPlanPolicy < ApplicationPolicy
|
||||
def index?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.is_admin? and record.destroyable?
|
||||
user.admin? and record.destroyable?
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,13 @@
|
||||
class PlanPolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.is_admin? and record.destroyable?
|
||||
user.admin? and record.destroyable?
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
class PriceCategoryPolicy < ApplicationPolicy
|
||||
%w(show create update destroy).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,9 +1,9 @@
|
||||
class PricePolicy < ApplicationPolicy
|
||||
def index?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
class PricingPolicy < ApplicationPolicy
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
@ -15,10 +15,10 @@ class ProjectPolicy < ApplicationPolicy
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin? or record.author == user or record.users.include?(user)
|
||||
user.admin? or record.author == user or record.users.include?(user)
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.is_admin? or record.author == user
|
||||
user.admin? or record.author == user
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
class ReservationPolicy < ApplicationPolicy
|
||||
def update?
|
||||
user.is_admin? or record.user == user
|
||||
user.admin? or record.user == user
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
class SettingPolicy < ApplicationPolicy
|
||||
%w(update).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -5,11 +5,11 @@ class SlotPolicy < ApplicationPolicy
|
||||
enabled = (Setting.find_by( name: 'booking_move_enable').value == 'true')
|
||||
|
||||
# these condition does not apply to admins
|
||||
user.is_admin? or
|
||||
user.admin? or
|
||||
(record.reservation.user == user and enabled and ((record.start_at - Time.now).to_i / 3600 >= delay))
|
||||
end
|
||||
|
||||
def cancel?
|
||||
user.is_admin? or record.reservation.user == user
|
||||
user.admin? or record.reservation.user == user
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,13 @@
|
||||
class SpacePolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.is_admin? and record.destroyable?
|
||||
user.admin? and record.destroyable?
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ class StatisticPolicy < ApplicationPolicy
|
||||
%w(index account event machine project subscription training user space scroll export_subscription export_machine
|
||||
export_training export_event export_account export_project export_space export_global).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,9 +1,9 @@
|
||||
class SubscriptionPolicy < ApplicationPolicy
|
||||
def show?
|
||||
user.is_admin? or record.user_id == user.id
|
||||
user.admin? or record.user_id == user.id
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,6 @@
|
||||
class TagPolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
|
@ -1,6 +1,6 @@
|
||||
class ThemePolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
|
@ -7,15 +7,15 @@ class TrainingPolicy < ApplicationPolicy
|
||||
|
||||
%w(create update).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.is_admin? and record.destroyable?
|
||||
user.admin? and record.destroyable?
|
||||
end
|
||||
|
||||
def availabilities?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
@ -1,20 +1,22 @@
|
||||
class UserPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
if user.is_admin?
|
||||
scope.includes(:group, :training_credits, :machine_credits, :subscriptions => [:plan => [:credits]], :profile => [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'").order('users.created_at desc')
|
||||
if user.admin?
|
||||
scope.includes(:group, :training_credits, :machine_credits, subscriptions: [plan: [:credits]], profile: [:user_avatar])
|
||||
.joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'").order('users.created_at desc')
|
||||
else
|
||||
scope.includes(:profile => [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'").where(is_allow_contact: true).order('users.created_at desc')
|
||||
scope.includes(profile: [:user_avatar]).joins(:roles).where("users.is_active = 'true' AND roles.name = 'member'")
|
||||
.where(is_allow_contact: true).order('users.created_at desc')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def show?
|
||||
user.is_admin? or (record.is_allow_contact and record.is_member?) or (user.id == record.id)
|
||||
user.admin? or (record.is_allow_contact and record.member?) or (user.id == record.id)
|
||||
end
|
||||
|
||||
def update?
|
||||
user.is_admin? or (user.id == record.id)
|
||||
user.admin? or (user.id == record.id)
|
||||
end
|
||||
|
||||
def destroy?
|
||||
@ -25,9 +27,9 @@ class UserPolicy < ApplicationPolicy
|
||||
user.id == record.id
|
||||
end
|
||||
|
||||
%w(list create mapping).each do |action|
|
||||
%w[list create mapping].each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
class VersionPolicy < ApplicationPolicy
|
||||
def show?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,13 @@
|
||||
class WalletPolicy < ApplicationPolicy
|
||||
def by_user?
|
||||
user.is_admin? or user == record.user
|
||||
user.admin? or user == record.user
|
||||
end
|
||||
|
||||
def transactions?
|
||||
user.is_admin? or user == record.user
|
||||
user.admin? or user == record.user
|
||||
end
|
||||
|
||||
def credit?
|
||||
user.is_admin?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user