mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-30 19:52:20 +01:00
define payment method before validating schedule
This commit is contained in:
parent
a56112a47f
commit
6abee0cea0
124
app/frontend/src/javascript/components/wallet-info.tsx
Normal file
124
app/frontend/src/javascript/components/wallet-info.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* This component displays a summary of the amount paid with the virtual wallet, for the current transaction
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { react2angular } from 'react2angular';
|
||||
import moment from 'moment';
|
||||
import { IApplication } from '../models/application';
|
||||
import '../lib/i18n';
|
||||
import { IFilterService } from 'angular';
|
||||
import { Loader } from './loader';
|
||||
import { Reservation } from '../models/reservation';
|
||||
import { User } from '../models/user';
|
||||
import { Wallet } from '../models/wallet';
|
||||
|
||||
declare var Application: IApplication;
|
||||
|
||||
interface WalletInfoProps {
|
||||
reservation: Reservation,
|
||||
$filter: IFilterService,
|
||||
currentUser: User,
|
||||
wallet: Wallet,
|
||||
price: number,
|
||||
remainingPrice: number,
|
||||
}
|
||||
|
||||
const WalletInfo: React.FC<WalletInfoProps> = ({ reservation, currentUser, wallet, price, remainingPrice, $filter }) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
/**
|
||||
* Return the formatted localized amount for the given price (eg. 20.5 => "20,50 €")
|
||||
*/
|
||||
const formatPrice = (price: number): string => {
|
||||
return $filter('currency')(price);
|
||||
}
|
||||
/**
|
||||
* Check if the currently connected used is also the person making the reservation.
|
||||
* If the currently connected user (ie. the operator), is an admin or a manager, he may book the reservation for someone else.
|
||||
*/
|
||||
const isOperatorAndClient = (): boolean => {
|
||||
return currentUser.id == reservation.user_id;
|
||||
}
|
||||
/**
|
||||
* If the client has some money in his wallet & the price is not zero, then we should display this component.
|
||||
*/
|
||||
const shouldBeShown = (): boolean => {
|
||||
return wallet.amount > 0 && price > 0;
|
||||
}
|
||||
/**
|
||||
* If the amount in the wallet is not enough to cover the whole price, then the user must pay the remaining price
|
||||
* using another payment mean.
|
||||
*/
|
||||
const hasRemainingPrice = (): boolean => {
|
||||
return remainingPrice > 0;
|
||||
}
|
||||
/**
|
||||
* Does the current cart contains a payment schedule?
|
||||
*/
|
||||
const isPaymentSchedule = (): boolean => {
|
||||
return reservation.plan_id && reservation.payment_schedule;
|
||||
}
|
||||
/**
|
||||
* Return the human-readable name of the item currently bought with the wallet
|
||||
*/
|
||||
const getPriceItem = (): string => {
|
||||
let item = 'other';
|
||||
if (reservation.slots_attributes.length > 0) {
|
||||
item = 'reservation';
|
||||
} else if (reservation.plan_id) {
|
||||
if (reservation.payment_schedule) {
|
||||
item = 'first_deadline';
|
||||
}
|
||||
else item = 'subscription';
|
||||
}
|
||||
|
||||
return t(`app.shared.wallet.wallet_info.item_${item}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="wallet-info">
|
||||
{shouldBeShown() && <div>
|
||||
{isOperatorAndClient() && <div>
|
||||
<h3>{t('app.shared.wallet.wallet_info.you_have_AMOUNT_in_wallet', {AMOUNT : formatPrice(wallet.amount)})}</h3>
|
||||
{!hasRemainingPrice() &&<p>
|
||||
{t('app.shared.wallet.wallet_info.wallet_pay_ITEM', {ITEM: getPriceItem()})}
|
||||
</p>}
|
||||
{hasRemainingPrice() &&<p>
|
||||
{t('app.shared.wallet.wallet_info.credit_AMOUNT_for_pay_ITEM', {
|
||||
AMOUNT: formatPrice(remainingPrice),
|
||||
ITEM: getPriceItem()
|
||||
})}
|
||||
</p>}
|
||||
</div>}
|
||||
{!isOperatorAndClient() && <div>
|
||||
<h3>{t('app.shared.wallet.wallet_info.client_have_AMOUNT_in_wallet', {AMOUNT : formatPrice(wallet.amount)})}</h3>
|
||||
{!hasRemainingPrice() &&<p>
|
||||
{t('app.shared.wallet.wallet_info.client_wallet_pay_ITEM', {ITEM: getPriceItem()})}
|
||||
</p>}
|
||||
{hasRemainingPrice() &&<p>
|
||||
{t('app.shared.wallet.wallet_info.client_credit_AMOUNT_for_pay_ITEM', {
|
||||
AMOUNT: formatPrice(remainingPrice),
|
||||
ITEM: getPriceItem()
|
||||
})}
|
||||
</p>}
|
||||
</div>}
|
||||
{!hasRemainingPrice() && isPaymentSchedule() &&<p className="info-deadlines">
|
||||
<i className="fa fa-warning" />
|
||||
<span>{t('app.shared.wallet.wallet_info.other_deadlines_no_wallet')}</span>
|
||||
</p>}
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const WalletInfoWrapper: React.FC<WalletInfoProps> = ({ currentUser, reservation, $filter, price, remainingPrice, wallet }) => {
|
||||
return (
|
||||
<Loader>
|
||||
<WalletInfo currentUser={currentUser} reservation={reservation} $filter={$filter} price={price} remainingPrice={remainingPrice} wallet={wallet} />
|
||||
</Loader>
|
||||
);
|
||||
}
|
||||
|
||||
Application.Components.component('walletInfo', react2angular(WalletInfoWrapper, ['currentUser', 'price', 'remainingPrice', 'reservation', 'wallet'], ['$filter']));
|
@ -738,7 +738,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
||||
const payOnSite = function (reservation) {
|
||||
$uibModal.open({
|
||||
templateUrl: '/shared/valid_reservation_modal.html',
|
||||
size: 'sm',
|
||||
size: $scope.schedule.payment_schedule ? 'lg' : 'sm',
|
||||
resolve: {
|
||||
reservation () {
|
||||
return reservation;
|
||||
@ -762,7 +762,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'Subscription', 'wallet', 'helpers', '$filter', 'coupon', 'selectedPlan', 'schedule',
|
||||
function ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, Subscription, wallet, helpers, $filter, coupon, selectedPlan, schedule) {
|
||||
// user wallet amount
|
||||
$scope.walletAmount = wallet.amount;
|
||||
$scope.wallet = wallet;
|
||||
|
||||
// Global price (total of all items)
|
||||
$scope.price = price.price;
|
||||
@ -783,18 +783,12 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
||||
$scope.schedule = schedule.payment_schedule;
|
||||
|
||||
// how should we collect payments for the payment schedule
|
||||
$scope.payment_method = 'stripe';
|
||||
$scope.method = {
|
||||
payment_method: 'stripe'
|
||||
};
|
||||
|
||||
// Button label
|
||||
if ($scope.amount > 0) {
|
||||
$scope.validButtonName = _t('app.shared.cart.confirm_payment_of_html', { ROLE: $rootScope.currentUser.role, AMOUNT: $filter('currency')($scope.amount) });
|
||||
} else {
|
||||
if ((price.price > 0) && ($scope.walletAmount === 0)) {
|
||||
$scope.validButtonName = _t('app.shared.cart.confirm_payment_of_html', { ROLE: $rootScope.currentUser.role, AMOUNT: $filter('currency')(price.price) });
|
||||
} else {
|
||||
$scope.validButtonName = _t('app.shared.buttons.confirm');
|
||||
}
|
||||
}
|
||||
// "valid" Button label
|
||||
$scope.validButtonName = '';
|
||||
|
||||
/**
|
||||
* Callback to process the local payment, triggered on button click
|
||||
@ -825,7 +819,47 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
||||
$scope.attempting = false;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Callback to close the modal without processing the payment
|
||||
*/
|
||||
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/**
|
||||
* Kind of constructor: these actions will be realized first when the directive is loaded
|
||||
*/
|
||||
const initialize = function () {
|
||||
$scope.$watch('method.payment_method', function (newValue, oldValue) {
|
||||
console.log(`watch triggered: ${newValue}`);
|
||||
$scope.validButtonName = computeValidButtonName();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the Label of the confirmation button
|
||||
*/
|
||||
const computeValidButtonName = function () {
|
||||
let method = '';
|
||||
if (AuthService.isAuthorized(['admin', 'manager']) && $rootScope.currentUser.id !== reservation.user_id) {
|
||||
method = $scope.method.payment_method;
|
||||
} else {
|
||||
method = 'stripe';
|
||||
}
|
||||
console.log(method);
|
||||
if ($scope.amount > 0) {
|
||||
return _t('app.shared.cart.confirm_payment_of_html', { METHOD: method, AMOUNT: $filter('currency')($scope.amount) });
|
||||
} else {
|
||||
if ((price.price > 0) && ($scope.wallet.amount === 0)) {
|
||||
return _t('app.shared.cart.confirm_payment_of_html', { METHOD: method, AMOUNT: $filter('currency')(price.price) });
|
||||
} else {
|
||||
return _t('app.shared.buttons.confirm');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// # !!! MUST BE CALLED AT THE END of the controller
|
||||
initialize();
|
||||
}
|
||||
]
|
||||
}).result.finally(null).then(function (reservation) { afterPayment(reservation); });
|
||||
@ -875,13 +909,23 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
||||
} else {
|
||||
if (AuthService.isAuthorized(['admin']) ||
|
||||
(AuthService.isAuthorized('manager') && $scope.user.id !== $rootScope.currentUser.id) ||
|
||||
amountToPay === 0) {
|
||||
(amountToPay === 0 && !hasOtherDeadlines())) {
|
||||
return payOnSite(reservation);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the later deadlines of the payment schedule exists and are not equal to zero
|
||||
* @return {boolean}
|
||||
*/
|
||||
const hasOtherDeadlines = function () {
|
||||
if (!$scope.schedule.payment_schedule) return false;
|
||||
if ($scope.schedule.payment_schedule.items.length < 2) return false;
|
||||
return $scope.schedule.payment_schedule.items[1].amount !== 0;
|
||||
};
|
||||
|
||||
// !!! MUST BE CALLED AT THE END of the directive
|
||||
return initialize();
|
||||
}
|
||||
|
15
app/frontend/src/javascript/models/reservation.ts
Normal file
15
app/frontend/src/javascript/models/reservation.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export interface ReservationSlot {
|
||||
start_at: Date,
|
||||
end_at: Date,
|
||||
availability_id: number,
|
||||
offered: boolean
|
||||
}
|
||||
|
||||
export interface Reservation {
|
||||
user_id: number,
|
||||
reservable_id: number,
|
||||
reservable_type: string,
|
||||
slots_attributes: Array<ReservationSlot>,
|
||||
plan_id: number
|
||||
payment_schedule: boolean
|
||||
}
|
6
app/frontend/src/javascript/models/wallet.ts
Normal file
6
app/frontend/src/javascript/models/wallet.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export interface Wallet {
|
||||
id: number,
|
||||
invoicing_profile_id: number,
|
||||
amount: number,
|
||||
user_id: number
|
||||
}
|
@ -23,5 +23,6 @@
|
||||
@import "modules/tour";
|
||||
@import "modules/fab-modal";
|
||||
@import "modules/payment-schedule-summary";
|
||||
@import "modules/wallet-info";
|
||||
|
||||
@import "app.responsive";
|
||||
|
25
app/frontend/src/stylesheets/modules/wallet-info.scss
Normal file
25
app/frontend/src/stylesheets/modules/wallet-info.scss
Normal file
@ -0,0 +1,25 @@
|
||||
.wallet-info {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
h3 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
p {
|
||||
font-style: italic;
|
||||
}
|
||||
.info-deadlines {
|
||||
border: 1px solid #faebcc;
|
||||
padding: 15px;
|
||||
color: #8a6d3b;
|
||||
background-color: #fcf8e3;
|
||||
border-radius: 4px;
|
||||
font-style: normal;
|
||||
display: flex;
|
||||
|
||||
i {
|
||||
vertical-align: middle;
|
||||
line-height: 2.5em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<div ng-if="currentUser.role != 'admin'">
|
||||
<h3 class="m-t-xs" ng-if="walletAmount > 0 && price > 0" ng-bind-html="'app.shared.wallet.you_have_amount_in_wallet' | translate:{ amount: numberFilter(walletAmount, 2), currency: currencySymbol }"></h3>
|
||||
<p ng-if="walletAmount > 0 && price > 0 && amount === 0" class="text-italic">{{'app.shared.wallet.wallet_pay_reservation' | translate}}</p>
|
||||
<p ng-if="walletAmount > 0 && amount !== 0" class="text-italic" ng-bind-html="'app.shared.stripe.credit_amount_for_pay_reservation' | translate:{ amount: numberFilter(amount, 2), currency: currencySymbol }"></p>
|
||||
</div>
|
||||
<div ng-if="currentUser.role == 'admin'">
|
||||
<h3 class="m-t-xs" ng-if="walletAmount > 0 && price > 0" ng-bind-html="'app.shared.wallet.client_have_amount_in_wallet' | translate:{ amount: numberFilter(walletAmount, 2), currency: currencySymbol }"></h3>
|
||||
<p ng-if="walletAmount > 0 && price > 0 && amount === 0" class="text-italic">{{'app.shared.wallet.client_wallet_pay_reservation' | translate}}</p>
|
||||
<p ng-if="walletAmount > 0 && amount !== 0" class="text-italic" ng-bind-html="'app.shared.stripe.client_credit_amount_for_pay_reservation' | translate:{ amount: numberFilter(amount, 2), currency: currencySymbol }"></p>
|
||||
</div>
|
@ -5,32 +5,45 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<uib-alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</uib-alert>
|
||||
<ng-include src="'/shared/_wallet_amount_info.html'"></ng-include>
|
||||
<div class="row">
|
||||
<div ng-class="{'col-md-6': schedule, 'm-h-sm': !schedule}">
|
||||
<div ng-if="reservation.slots_attributes.length > 0">
|
||||
<p translate>{{ 'app.shared.valid_reservation_modal.here_is_the_summary_of_the_slots_to_book_for_the_current_user' }}</p>
|
||||
<ul ng-repeat="slot in reservation.slots_attributes">
|
||||
<li><strong>{{slot.start_at | amDateFormat: 'LL'}} : {{slot.start_at | amDateFormat:'LT'}} - {{slot.end_at | amDateFormat:'LT'}}</strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div ng-if="reservation.plan_id">
|
||||
<p translate>{{ 'app.shared.valid_reservation_modal.here_is_the_subscription_summary' }}</p>
|
||||
<p>{{ plan | humanReadablePlanName }}</p>
|
||||
</div>
|
||||
<div ng-if="schedule">
|
||||
<label for="method" translate>{{ 'app.shared.valid_reservation_modal.payment_method' }}</label>
|
||||
<select id="method"
|
||||
class="form-control m-b"
|
||||
ng-model="method.payment_method">
|
||||
<option value="stripe" translate>{{ 'app.shared.valid_reservation_modal.method_stripe' }}</option>
|
||||
<option value="check" translate>{{ 'app.shared.valid_reservation_modal.method_check' }}</option>
|
||||
</select>
|
||||
<p ng-show="method.payment_method == 'stripe'" translate>{{ 'app.shared.valid_reservation_modal.stripe_collection_info' }}</p>
|
||||
<p ng-show="method.payment_method == 'check'" translate translate-values="{DEADLINES: schedule.items.length}">{{ 'app.shared.valid_reservation_modal.check_collection_info' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6" ng-if="schedule">
|
||||
<ul class="full-schedule">
|
||||
<li ng-repeat="item in schedule.items">
|
||||
<span class="schedule-item-date">{{item.due_date | amDateFormat: 'L'}}</span>
|
||||
<span> </span>
|
||||
<span class="schedule-item-price">{{item.amount | currency}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div ng-if="reservation.slots_attributes.length > 0">
|
||||
<p translate>{{ 'app.shared.valid_reservation_modal.here_is_the_summary_of_the_slots_to_book_for_the_current_user' }}</p>
|
||||
<ul ng-repeat="slot in reservation.slots_attributes">
|
||||
<li><strong>{{slot.start_at | amDateFormat: 'LL'}} : {{slot.start_at | amDateFormat:'LT'}} - {{slot.end_at | amDateFormat:'LT'}}</strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div ng-if="reservation.plan_id">
|
||||
<p translate>{{ 'app.shared.valid_reservation_modal.here_is_the_subscription_summary' }}</p>
|
||||
<p>{{ plan | humanReadablePlanName }}</p>
|
||||
</div>
|
||||
<div ng-if="schedule">
|
||||
<payment-schedule-summary schedule="schedule"></payment-schedule-summary>
|
||||
<label for="method" translate>{{ 'app.shared.valid_reservation_modal.payment_method' }}</label>
|
||||
<select id="method"
|
||||
class="form-control m-b"
|
||||
ng-model="payment_method">
|
||||
<option value="stripe" translate>{{ 'app.shared.valid_reservation_modal.method_stripe' }}</option>
|
||||
<option value="check" translate>{{ 'app.shared.valid_reservation_modal.method_check' }}</option>
|
||||
<!-- TODO, pay 1st deadline with wallet -->
|
||||
<!-- TODO, notify about unable to pay with the wallet -->
|
||||
<!-- TODO, compute 1st deadline with wallet -->
|
||||
</select>
|
||||
<p ng-show="payment_method == 'stripe'" translate>{{ 'app.shared.valid_reservation_modal.stripe_collection_info' }}</p>
|
||||
<p ng-show="payment_method == 'check'" translate translate-values="{DEADLINES: schedule.items.length}">{{ 'app.shared.valid_reservation_modal.check_collection_info' }}</p>
|
||||
<wallet-info current-user="currentUser"
|
||||
reservation="reservation"
|
||||
price="price"
|
||||
remaining-price="amount"
|
||||
wallet="wallet"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
@ -129,7 +129,11 @@ en:
|
||||
here_is_the_summary_of_the_slots_to_book_for_the_current_user: "Here is the summary of the slots to book for the current user:"
|
||||
subscription_confirmation: "Subscription confirmation"
|
||||
here_is_the_subscription_summary: "Here is the subscription summary:"
|
||||
payment_schedule: "This subscription is payed with a payment schedule of {DEADLINES} months. By validating, you confirm to collect the first monthly payment."
|
||||
payment_method: "Payment method"
|
||||
method_stripe: "Online by card"
|
||||
method_check: "By check"
|
||||
stripe_collection_info: "By validating, you'll be prompted for the member's card number. This card will be automatically charged at the deadlines."
|
||||
check_collection_info: "By validating, you confirm that you have {DEADLINES} checks, allowing you to collect all the monthly payments."
|
||||
#event edition form
|
||||
event:
|
||||
title: "Title"
|
||||
@ -321,15 +325,23 @@ en:
|
||||
amount_minimum_1: "The amount minimum is 1"
|
||||
amount_confirm_is_required: "The amount confirmation is required."
|
||||
amount_confirm_does_not_match: "The amount confirmation does not match."
|
||||
you_have_amount_in_wallet: "You have {amount} {currency} in your wallet"
|
||||
client_have_amount_in_wallet: "Client has {amount} {currency} in wallet"
|
||||
wallet_pay_reservation: "You can pay your reservation directly"
|
||||
client_wallet_pay_reservation: "The member can pay his reservation directly"
|
||||
debit_subscription: "Pay for a subscription"
|
||||
debit_reservation_training: "Pay for a training reservation"
|
||||
debit_reservation_machine: "Pay for a machine reservation"
|
||||
debit_reservation_event: "Pay for an event reservation"
|
||||
warning_uneditable_credit: "Warning: once validated, the credited amount won't be editable anymore."
|
||||
wallet_info:
|
||||
you_have_AMOUNT_in_wallet: "You have {AMOUNT} on your wallet"
|
||||
wallet_pay_ITEM: "You pay your {ITEM} directly."
|
||||
item_reservation: "reservation"
|
||||
item_subscription: "subscription"
|
||||
item_first_deadline: "first deadline"
|
||||
item_other: "purchase"
|
||||
credit_AMOUNT_for_pay_ITEM: "You still have {AMOUNT} to pay to validate your {ITEM}."
|
||||
client_have_AMOUNT_in_wallet: "The member has {AMOUNT} on his wallet"
|
||||
client_wallet_pay_ITEM: "The member can directly pay his {ITEM}."
|
||||
client_credit_AMOUNT_for_pay_ITEM: "{AMOUNT} are remaining to pay to validate the {ITEM}"
|
||||
other_deadlines_no_wallet: "Warning: the remaining wallet balance cannot be used for the next deadlines."
|
||||
#coupon (promotional) (creation/edition form)
|
||||
coupon:
|
||||
name: "Name"
|
||||
|
@ -325,15 +325,23 @@ fr:
|
||||
amount_minimum_1: "Le montant minimum est de 1"
|
||||
amount_confirm_is_required: "La confirmation du montant est requise."
|
||||
amount_confirm_does_not_match: "La confirmation du montant ne correspond pas."
|
||||
you_have_amount_in_wallet: "Vous avez {amount} {currency} sur votre porte-monnaie"
|
||||
client_have_amount_in_wallet: "Le client a {amount} {currency} sur son porte-monnaie"
|
||||
wallet_pay_reservation: "Vous pouvez payer votre réservation directement"
|
||||
client_wallet_pay_reservation: "Le membre peut directement payer sa réservation"
|
||||
debit_subscription: "Payer un abonnement"
|
||||
debit_reservation_training: "Payer une réservation de formation"
|
||||
debit_reservation_machine: "Payer une réservation de machine"
|
||||
debit_reservation_event: "Payer une réservation d'événement"
|
||||
warning_uneditable_credit: "Attention : une fois validé, le montant crédité ne sera plus modifiable."
|
||||
wallet_info:
|
||||
you_have_AMOUNT_in_wallet: "Vous avez {AMOUNT} sur votre porte-monnaie"
|
||||
wallet_pay_ITEM: "Vous pouvez payer votre {ITEM} directement."
|
||||
item_reservation: "réservation"
|
||||
item_subscription: "abonnement"
|
||||
item_first_deadline: "première échéance"
|
||||
item_other: "achat"
|
||||
credit_AMOUNT_for_pay_ITEM: "Il vous reste {AMOUNT} à payer pour valider votre {ITEM}."
|
||||
client_have_AMOUNT_in_wallet: "Le membre a {AMOUNT} sur son porte-monnaie"
|
||||
client_wallet_pay_ITEM: "Le membre peut directement payer {ITEM, select, abonnement{son} achat{son} other{sa}} {ITEM}."
|
||||
client_credit_AMOUNT_for_pay_ITEM: "Il reste {AMOUNT} à payer pour valider {ITEM, select, abonnement{l'} achat{l'} other{la }}{ITEM}"
|
||||
other_deadlines_no_wallet: "Attention : le solde du porte-monnaie ne pourra pas être utilisé pour les échéances suivantes."
|
||||
#coupon (promotional) (creation/edition form)
|
||||
coupon:
|
||||
name: "Nom"
|
||||
@ -433,7 +441,7 @@ fr:
|
||||
do_you_really_want_to_cancel_this_reservation_html: "<p>Êtes-vous sur de vouloir annuler cette réservation ?</p><p>Attention : si cette réservation a été effectuée gratuitement, dans le cadre d'un abonnement, les crédits utilisés ne seront pas re-crédités.</p>"
|
||||
reservation_was_cancelled_successfully: "La réservation a bien été annulée."
|
||||
cancellation_failed: "L'annulation a échouée."
|
||||
confirm_payment_of_html: "{ROLE, select, admin{Paiement sur place} other{Payer}} : {AMOUNT}" #eg. confirm my payment of $20.00
|
||||
confirm_payment_of_html: "{METHOD, select, stripe{Payer par carte} other{Paiement sur place}} : {AMOUNT}" #eg. confirm my payment of $20.00
|
||||
a_problem_occurred_during_the_payment_process_please_try_again_later: "Il y a eu un problème lors de la procédure de paiement. Veuillez réessayer plus tard."
|
||||
none: "Aucune"
|
||||
online_payment_disabled: "Le paiement par carte bancaire n'est pas disponible. Merci de contacter directement l'accueil du FabLab."
|
||||
|
Loading…
x
Reference in New Issue
Block a user