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

adjust payment schedule table to usage by admins & members

This commit is contained in:
Sylvain 2021-02-10 10:03:04 +01:00
parent 16bb4bc76d
commit 9609d96fc3
19 changed files with 165 additions and 129 deletions

View File

@ -33,9 +33,13 @@ function extractHumanReadableMessage(error: any): string {
return error;
}
// parse Rails errors (as JSON)
// parse Rails errors (as JSON) or API errors
let message = '';
if (error instanceof Object) {
// API errors
if (error.hasOwnProperty('error') && typeof error.error === 'string') {
return error.error;
}
// iterate through all the keys to build the message
for (const key in error) {
if (Object.prototype.hasOwnProperty.call(error, key)) {

View File

@ -38,15 +38,5 @@ export default class PaymentScheduleAPI {
const res: AxiosResponse = await apiClient.put(`/api/payment_schedules/${paymentScheduleId}/cancel`);
return res?.data;
}
static list (query: PaymentScheduleIndexRequest): IWrapPromise<Array<PaymentSchedule>> {
const api = new PaymentScheduleAPI();
return wrapPromise(api.list(query));
}
static index(query: PaymentScheduleIndexRequest): IWrapPromise<Array<PaymentSchedule>> {
const api = new PaymentScheduleAPI();
return wrapPromise(api.index(query));
}
}

View File

@ -3,7 +3,7 @@
* for the currentUser
*/
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { IApplication } from '../models/application';
import { useTranslation } from 'react-i18next';
import { Loader } from './loader';
@ -12,6 +12,7 @@ import PaymentScheduleAPI from '../api/payment-schedule';
import { PaymentSchedulesTable } from './payment-schedules-table';
import { FabButton } from './fab-button';
import { User } from '../models/user';
import { PaymentSchedule } from '../models/payment-schedule';
declare var Application: IApplication;
@ -20,13 +21,16 @@ interface PaymentSchedulesDashboardProps {
}
const PAGE_SIZE = 20;
const paymentSchedulesIndex = PaymentScheduleAPI.index({ query: { page: 1, size: PAGE_SIZE } });
const PaymentSchedulesDashboard: React.FC<PaymentSchedulesDashboardProps> = ({ currentUser }) => {
const { t } = useTranslation('logged');
const [paymentSchedules, setPaymentSchedules] = useState(paymentSchedulesIndex.read());
const [pageNumber, setPageNumber] = useState(1);
const [paymentSchedules, setPaymentSchedules] = useState<Array<PaymentSchedule>>([]);
const [pageNumber, setPageNumber] = useState<number>(1);
useEffect(() => {
handleRefreshList();
}, []);
/**
* Fetch from the API the next payment schedules to display, for the current filters, and append them to the current results table.
@ -44,10 +48,12 @@ const PaymentSchedulesDashboard: React.FC<PaymentSchedulesDashboardProps> = ({ c
/**
* Reload from te API all the currently displayed payment schedules
*/
const handleRefreshList = (): void => {
const handleRefreshList = (onError?: (msg: any) => void): void => {
const api = new PaymentScheduleAPI();
api.index({ query: { page: 1, size: PAGE_SIZE * pageNumber }}).then((res) => {
setPaymentSchedules(res);
}).catch((err) => {
if (typeof onError === 'function') { onError(err.message); }
});
}
@ -67,10 +73,10 @@ const PaymentSchedulesDashboard: React.FC<PaymentSchedulesDashboardProps> = ({ c
return (
<div className="payment-schedules-dashboard">
{!hasSchedules() && <div>{t('app.admin.invoices.payment_schedules.no_payment_schedules')}</div>}
{!hasSchedules() && <div>{t('app.logged.dashboard.payment_schedules.no_payment_schedules')}</div>}
{hasSchedules() && <div className="schedules-list">
<PaymentSchedulesTable paymentSchedules={paymentSchedules} showCustomer={false} refreshList={handleRefreshList} operator={currentUser} />
{hasMoreSchedules() && <FabButton className="load-more" onClick={handleLoadMore}>{t('app.admin.invoices.payment_schedules.load_more')}</FabButton>}
{hasMoreSchedules() && <FabButton className="load-more" onClick={handleLoadMore}>{t('app.logged.dashboard.payment_schedules.load_more')}</FabButton>}
</div>}
</div>
);

View File

@ -2,7 +2,7 @@
* This component shows a list of all payment schedules with their associated deadlines (aka. PaymentScheduleItem) and invoices
*/
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { IApplication } from '../models/application';
import { useTranslation } from 'react-i18next';
import { Loader } from './loader';
@ -12,6 +12,7 @@ import { DocumentFilters } from './document-filters';
import { PaymentSchedulesTable } from './payment-schedules-table';
import { FabButton } from './fab-button';
import { User } from '../models/user';
import { PaymentSchedule } from '../models/payment-schedule';
declare var Application: IApplication;
@ -20,16 +21,19 @@ interface PaymentSchedulesListProps {
}
const PAGE_SIZE = 20;
const paymentSchedulesList = PaymentScheduleAPI.list({ query: { page: 1, size: PAGE_SIZE } });
const PaymentSchedulesList: React.FC<PaymentSchedulesListProps> = ({ currentUser }) => {
const { t } = useTranslation('admin');
const [paymentSchedules, setPaymentSchedules] = useState(paymentSchedulesList.read());
const [pageNumber, setPageNumber] = useState(1);
const [referenceFilter, setReferenceFilter] = useState(null);
const [customerFilter, setCustomerFilter] = useState(null);
const [dateFilter, setDateFilter] = useState(null);
const [paymentSchedules, setPaymentSchedules] = useState<Array<PaymentSchedule>>([]);
const [pageNumber, setPageNumber] = useState<number>(1);
const [referenceFilter, setReferenceFilter] = useState<string>(null);
const [customerFilter, setCustomerFilter] = useState<string>(null);
const [dateFilter, setDateFilter] = useState<Date>(null);
useEffect(() => {
handleRefreshList();
}, []);
/**
* Fetch from the API the payments schedules matching the given filters and reset the results table with the new schedules.
@ -61,10 +65,12 @@ const PaymentSchedulesList: React.FC<PaymentSchedulesListProps> = ({ currentUser
/**
* Reload from te API all the currently displayed payment schedules
*/
const handleRefreshList = (): void => {
const handleRefreshList = (onError?: (msg: any) => void): void => {
const api = new PaymentScheduleAPI();
api.list({ query: { reference: referenceFilter, customer: customerFilter, date: dateFilter, page: 1, size: PAGE_SIZE * pageNumber }}).then((res) => {
setPaymentSchedules(res);
}).catch((err) => {
if (typeof onError === 'function') { onError(err.message); }
});
}

View File

@ -25,12 +25,12 @@ declare var Fablab: IFablab;
interface PaymentSchedulesTableProps {
paymentSchedules: Array<PaymentSchedule>,
showCustomer?: boolean,
refreshList: () => void,
refreshList: (onError: (msg: any) => void) => void,
operator: User,
}
const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({ paymentSchedules, showCustomer, refreshList, operator }) => {
const { t } = useTranslation('admin');
const { t } = useTranslation('shared');
const [showExpanded, setShowExpanded] = useState<Map<number, boolean>>(new Map());
const [showConfirmCashing, setShowConfirmCashing] = useState<boolean>(false);
@ -114,7 +114,7 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
return (
<a href={link} target="_blank" className="download-button">
<i className="fas fa-download" />
{t('app.admin.invoices.schedules_table.download')}
{t('app.shared.schedules_table.download')}
</a>
);
}
@ -123,9 +123,9 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
* Return the human-readable string for the status of the provided deadline.
*/
const formatState = (item: PaymentScheduleItem): JSX.Element => {
let res = t(`app.admin.invoices.schedules_table.state_${item.state}`);
let res = t(`app.shared.schedules_table.state_${item.state}`);
if (item.state === PaymentScheduleItemState.Paid) {
const key = `app.admin.invoices.schedules_table.method_${item.payment_method}`
const key = `app.shared.schedules_table.method_${item.payment_method}`
res += ` (${t(key)})`;
}
return <span className={`state-${item.state}`}>{res}</span>;
@ -150,24 +150,24 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
return (
<FabButton onClick={handleConfirmCheckPayment(item)}
icon={<i className="fas fa-money-check" />}>
{t('app.admin.invoices.schedules_table.confirm_payment')}
{t('app.shared.schedules_table.confirm_payment')}
</FabButton>
);
} else {
return <span>{t('app.admin.invoices.schedules_table.please_ask_reception')}</span>
return <span>{t('app.shared.schedules_table.please_ask_reception')}</span>
}
case PaymentScheduleItemState.RequireAction:
return (
<FabButton onClick={handleSolveAction(item)}
icon={<i className="fas fa-wrench" />}>
{t('app.admin.invoices.schedules_table.solve')}
{t('app.shared.schedules_table.solve')}
</FabButton>
);
case PaymentScheduleItemState.RequirePaymentMethod:
return (
<FabButton onClick={handleUpdateCard(item, schedule)}
icon={<i className="fas fa-credit-card" />}>
{t('app.admin.invoices.schedules_table.update_card')}
{t('app.shared.schedules_table.update_card')}
</FabButton>
);
case PaymentScheduleItemState.Error:
@ -175,11 +175,11 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
return (
<FabButton onClick={handleCancelSubscription(schedule)}
icon={<i className="fas fa-times" />}>
{t('app.admin.invoices.schedules_table.cancel_subscription')}
{t('app.shared.schedules_table.cancel_subscription')}
</FabButton>
)
} else {
return <span>{t('app.admin.invoices.schedules_table.please_ask_reception')}</span>
return <span>{t('app.shared.schedules_table.please_ask_reception')}</span>
}
default:
return <span />
@ -203,12 +203,19 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
const api = new PaymentScheduleAPI();
api.cashCheck(tempDeadline.id).then((res) => {
if (res.state === PaymentScheduleItemState.Paid) {
refreshList();
refreshSchedulesTable();
toggleConfirmCashingModal();
}
});
}
/**
* Refresh all payment schedules in the table
*/
const refreshSchedulesTable = (): void => {
refreshList(setErrors);
}
/**
* Show/hide the modal dialog that enable to confirm the cashing of the check for a given deadline.
*/
@ -240,7 +247,7 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
toggleConfirmActionButton();
const api = new PaymentScheduleAPI();
api.refreshItem(tempDeadline.id).then(() => {
refreshList();
refreshSchedulesTable();
toggleResolveActionModal();
});
}
@ -297,10 +304,10 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
const handleCardUpdateSuccess = (): void => {
const api = new PaymentScheduleAPI();
api.payItem(tempDeadline.id).then(() => {
refreshList();
refreshSchedulesTable();
toggleUpdateCardModal();
}).catch((err) => {
handleCardUpdateError(err.error);
handleCardUpdateError(err);
});
}
@ -335,7 +342,7 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
const onCancelSubscriptionConfirmed = (): void => {
const api = new PaymentScheduleAPI();
api.cancel(tempSchedule.id).then(() => {
refreshList();
refreshSchedulesTable();
toggleCancelSubscriptionModal();
});
}
@ -346,16 +353,16 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
<thead>
<tr>
<th className="w-35" />
<th className="w-200">{t('app.admin.invoices.schedules_table.schedule_num')}</th>
<th className="w-200">{t('app.admin.invoices.schedules_table.date')}</th>
<th className="w-120">{t('app.admin.invoices.schedules_table.price')}</th>
{showCustomer && <th className="w-200">{t('app.admin.invoices.schedules_table.customer')}</th>}
<th className="w-200">{t('app.shared.schedules_table.schedule_num')}</th>
<th className="w-200">{t('app.shared.schedules_table.date')}</th>
<th className="w-120">{t('app.shared.schedules_table.price')}</th>
{showCustomer && <th className="w-200">{t('app.shared.schedules_table.customer')}</th>}
<th className="w-200"/>
</tr>
</thead>
<tbody>
{paymentSchedules.map(p => <tr key={p.id}>
<td colSpan={6}>
<td colSpan={showCustomer ? 6 : 5}>
<table className="schedules-table-body">
<tbody>
<tr>
@ -368,14 +375,14 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
</tr>
<tr style={{ display: statusDisplay(p.id) }}>
<td className="w-35" />
<td colSpan={5}>
<td colSpan={showCustomer ? 5 : 4}>
<div>
<table className="schedule-items-table">
<thead>
<tr>
<th className="w-120">{t('app.admin.invoices.schedules_table.deadline')}</th>
<th className="w-120">{t('app.admin.invoices.schedules_table.amount')}</th>
<th className="w-200">{t('app.admin.invoices.schedules_table.state')}</th>
<th className="w-120">{t('app.shared.schedules_table.deadline')}</th>
<th className="w-120">{t('app.shared.schedules_table.amount')}</th>
<th className="w-200">{t('app.shared.schedules_table.state')}</th>
<th className="w-200" />
</tr>
</thead>
@ -398,37 +405,37 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
</tbody>
</table>
<div className="modals">
<FabModal title={t('app.admin.invoices.schedules_table.confirm_check_cashing')}
<FabModal title={t('app.shared.schedules_table.confirm_check_cashing')}
isOpen={showConfirmCashing}
toggleModal={toggleConfirmCashingModal}
onConfirm={onCheckCashingConfirmed}
closeButton={true}
confirmButton={t('app.admin.invoices.schedules_table.confirm_button')}>
confirmButton={t('app.shared.schedules_table.confirm_button')}>
{tempDeadline && <span>
{t('app.admin.invoices.schedules_table.confirm_check_cashing_body', {
{t('app.shared.schedules_table.confirm_check_cashing_body', {
AMOUNT: formatPrice(tempDeadline.amount),
DATE: formatDate(tempDeadline.due_date)
})}
</span>}
</FabModal>
<FabModal title={t('app.admin.invoices.schedules_table.cancel_subscription')}
<FabModal title={t('app.shared.schedules_table.cancel_subscription')}
isOpen={showCancelSubscription}
toggleModal={toggleCancelSubscriptionModal}
onConfirm={onCancelSubscriptionConfirmed}
closeButton={true}
confirmButton={t('app.admin.invoices.schedules_table.confirm_button')}>
{t('app.admin.invoices.schedules_table.confirm_cancel_subscription')}
confirmButton={t('app.shared.schedules_table.confirm_button')}>
{t('app.shared.schedules_table.confirm_cancel_subscription')}
</FabModal>
<StripeElements>
<FabModal title={t('app.admin.invoices.schedules_table.resolve_action')}
<FabModal title={t('app.shared.schedules_table.resolve_action')}
isOpen={showResolveAction}
toggleModal={toggleResolveActionModal}
onConfirm={afterAction}
confirmButton={t('app.admin.invoices.schedules_table.ok_button')}
confirmButton={t('app.shared.schedules_table.ok_button')}
preventConfirm={isConfirmActionDisabled}>
{tempDeadline && <StripeConfirm clientSecret={tempDeadline.client_secret} onResponse={toggleConfirmActionButton} />}
</FabModal>
<FabModal title={t('app.admin.invoices.schedules_table.update_card')}
<FabModal title={t('app.shared.schedules_table.update_card')}
isOpen={showUpdateCard}
toggleModal={toggleUpdateCardModal}
closeButton={false}
@ -445,7 +452,7 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
</div>}
</StripeCardUpdate>}
<div className="submit-card">
{canSubmitUpdateCard && <button type="submit" disabled={!canSubmitUpdateCard} form="stripe-card" className="submit-card-btn">{t('app.admin.invoices.schedules_table.validate_button')}</button>}
{canSubmitUpdateCard && <button type="submit" disabled={!canSubmitUpdateCard} form="stripe-card" className="submit-card-btn">{t('app.shared.schedules_table.validate_button')}</button>}
{!canSubmitUpdateCard && <div className="payment-pending">
<div className="fa-2x">
<i className="fas fa-circle-notch fa-spin" />

View File

@ -292,8 +292,8 @@
background-color: $bg-gray;
.wrap, .wrap-monthly {
width: 120px;
height: 120px;
width: 130px;
height: 130px;
display: inline-block;
background: white;
@ -302,7 +302,7 @@
border: 3px solid;
.price {
width: 104px;
width: 114px;
display: flex;
flex-direction: column;
justify-content: center;
@ -327,14 +327,14 @@
position: relative;
top: 5px;
left: 5px;
height: 104px;
height: 114px;
background-color: black;
.amount {
padding-left: 4px;
padding-right: 4px;
font-weight: bold;
font-size: rem-calc(18);
font-size: rem-calc(17);
color: white;
}

View File

@ -31,5 +31,6 @@
@import "modules/payment-schedules-table";
@import "modules/payment-schedules-list";
@import "modules/stripe-confirm";
@import "modules/payment-schedule-dashboard";
@import "app.responsive";

View File

@ -0,0 +1,12 @@
.payment-schedules-dashboard {
margin: 30px 15px 15px;
.schedules-list {
text-align: center;
.load-more {
margin-top: 2em;
}
}
}

View File

@ -134,6 +134,7 @@
.stripe-errors {
padding: 4px 0;
color: #9e2146;
overflow: auto;
}
}
.submit-card {

View File

@ -12,6 +12,7 @@
.stripe-errors {
padding: 4px 0;
color: #9e2146;
overflow: auto;
margin-bottom: 1.2em;
}
}

View File

@ -7,4 +7,4 @@
DATE: I18n.l(@attached_object.due_date, format: :long)) %>
<%= t('.body.error') %>
</p>
<p><%= t('.body.action', DASHBOARD: link_to(t('.body.your_dashboard'), "#{root_url}#!/dashboard/payment_schedules")) %></p>
<p><%= t('.body.action_html', DASHBOARD: link_to(t('.body.your_dashboard'), "#{root_url}#!/dashboard/payment_schedules")) %></p>

View File

@ -644,36 +644,6 @@ en:
filter_schedules: "Filter schedules"
no_payment_schedules: "No payment schedules to display"
load_more: "Load more"
schedules_table:
schedule_num: "Schedule #"
date: "Date"
price: "Price"
customer: "Customer"
deadline: "Deadline"
amount: "Amount"
state: "State"
download: "Download"
state_new: "Not yet due"
state_pending: "Waiting for the cashing of the check"
state_requires_payment_method: "The credit card must be updated"
state_requires_action: "Action required"
state_paid: "Paid"
state_error: "Error"
state_canceled: "Canceled"
method_stripe: "by card"
method_check: "by check"
confirm_payment: "Confirm payment"
solve: "Solve"
update_card: "Update the card"
confirm_check_cashing: "Confirm the cashing of the check"
confirm_check_cashing_body: "You must cash a check of {AMOUNT} for the deadline of {DATE}. By confirming the cashing of the check, an invoice will be generated for this due date."
confirm_button: "Confirm"
resolve_action: "Resolve the action"
ok_button: "OK"
validate_button: "Validate the new card"
cancel_subscription: "Cancel the subscription"
confirm_cancel_subscription: "You're about to cancel this payment schedule and the related subscription. Are you sure?"
please_ask_reception: "For any questions, please contact the FabLab's reception."
document_filters:
reference: "Reference"
customer: "Customer"

View File

@ -644,36 +644,6 @@ fr:
filter_schedules: "Filtrer les échéanciers"
no_payment_schedules: "Pas d'échéancier à afficher"
load_more: "Voir plus"
schedules_table:
schedule_num: "Échéancier n°"
date: "Date"
price: "Prix"
customer: "Client"
deadline: "Échéance"
amount: "Montant"
state: "État"
download: "Télécharger"
state_new: "Pas encore à l'échéance"
state_pending: "En attente de l'encaissement du chèque"
state_requires_payment_method: "La carte bancaire doit être mise à jour"
state_requires_action: "Action requise"
state_paid: "Payée"
state_error: "Erreur"
state_canceled: "Annulée"
method_stripe: "par carte"
method_check: "par chèque"
confirm_payment: "Confirmer l'encaissement"
solve: "Résoudre"
update_card: "Mettre à jour la carte"
confirm_check_cashing: "Confirmer l'encaissement du chèque"
confirm_check_cashing_body: "Vous devez encaisser un chèque de {AMOUNT} pour l'échéance du {DATE}. En confirmant l'encaissement du chèque, une facture sera générée pour cette échéance."
confirm_button: "Confirmer"
resolve_action: "Résoudre l'action"
ok_button: "OK"
validate_button: "Valider la nouvelle carte"
cancel_subscription: "Annuler l'abonnement"
confirm_cancel_subscription: "Vous êtes sur le point d'annuler cet échéancier de paiement ainsi que l'abonnement lié. Êtes-vous sur ?"
please_ask_reception: "Pour toute question, merci de contacter l'accueil du FabLab."
document_filters:
reference: "Référence"
customer: "Client"

View File

@ -125,6 +125,9 @@ en:
download_the_invoice: "Download the invoice"
download_the_credit_note: "Download the refund invoice"
no_invoices_for_now: "No invoices for now."
payment_schedules:
no_payment_schedules: "No payment schedules to display"
load_more: "Load more"
#public profil of a member
members_show:
members_list: "Members list"

View File

@ -125,6 +125,9 @@ fr:
download_the_invoice: "Télécharger la facture"
download_the_credit_note: "Télécharger l'avoir"
no_invoices_for_now: "Aucune facture pour le moment."
payment_schedules:
no_payment_schedules: "Pas d'échéancier à afficher"
load_more: "Voir plus"
#public profil of a member
members_show:
members_list: "Liste des membres"

View File

@ -478,3 +478,34 @@ en:
stripe_confirm:
pending: "Pending for action..."
success: "Thank you, your card setup is complete. The payment will be proceeded shortly."
# the summary table of all payment schedules
schedules_table:
schedule_num: "Schedule #"
date: "Date"
price: "Price"
customer: "Customer"
deadline: "Deadline"
amount: "Amount"
state: "State"
download: "Download"
state_new: "Not yet due"
state_pending: "Waiting for the cashing of the check"
state_requires_payment_method: "The credit card must be updated"
state_requires_action: "Action required"
state_paid: "Paid"
state_error: "Error"
state_canceled: "Canceled"
method_stripe: "by card"
method_check: "by check"
confirm_payment: "Confirm payment"
solve: "Solve"
update_card: "Update the card"
confirm_check_cashing: "Confirm the cashing of the check"
confirm_check_cashing_body: "You must cash a check of {AMOUNT} for the deadline of {DATE}. By confirming the cashing of the check, an invoice will be generated for this due date."
confirm_button: "Confirm"
resolve_action: "Resolve the action"
ok_button: "OK"
validate_button: "Validate the new card"
cancel_subscription: "Cancel the subscription"
confirm_cancel_subscription: "You're about to cancel this payment schedule and the related subscription. Are you sure?"
please_ask_reception: "For any questions, please contact the FabLab's reception."

View File

@ -478,3 +478,34 @@ fr:
stripe_confirm:
pending: "En attente de l'action ..."
success: "Merci, la configuration de votre carte est terminée. Le paiement sera effectué sous peu."
# the summary table of all payment schedules
schedules_table:
schedule_num: "Échéancier n°"
date: "Date"
price: "Prix"
customer: "Client"
deadline: "Échéance"
amount: "Montant"
state: "État"
download: "Télécharger"
state_new: "Pas encore à l'échéance"
state_pending: "En attente de l'encaissement du chèque"
state_requires_payment_method: "La carte bancaire doit être mise à jour"
state_requires_action: "Action requise"
state_paid: "Payée"
state_error: "Erreur"
state_canceled: "Annulée"
method_stripe: "par carte"
method_check: "par chèque"
confirm_payment: "Confirmer l'encaissement"
solve: "Résoudre"
update_card: "Mettre à jour la carte"
confirm_check_cashing: "Confirmer l'encaissement du chèque"
confirm_check_cashing_body: "Vous devez encaisser un chèque de {AMOUNT} pour l'échéance du {DATE}. En confirmant l'encaissement du chèque, une facture sera générée pour cette échéance."
confirm_button: "Confirmer"
resolve_action: "Résoudre l'action"
ok_button: "OK"
validate_button: "Valider la nouvelle carte"
cancel_subscription: "Annuler l'abonnement"
confirm_cancel_subscription: "Vous êtes sur le point d'annuler cet échéancier de paiement ainsi que l'abonnement lié. Êtes-vous sur ?"
please_ask_reception: "Pour toute question, merci de contacter l'accueil du FabLab."

View File

@ -305,7 +305,7 @@ en:
body:
remember: "In accordance with your %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}."
error: "Unfortunately, this card debit was unable to complete successfully."
action: "Please check %{DASHBOARD} or contact a manager before 24 hours, otherwise your subscription may be interrupted."
action_html: "Please check %{DASHBOARD} or contact a manager before 24 hours, otherwise your subscription may be interrupted."
your_dashboard: "your dashboard"
notify_admin_payment_schedule_check_deadline:
subject: "Payment deadline"

View File

@ -305,7 +305,7 @@ fr:
body:
remember: "Conformément à votre échéancier de paiement %{REFERENCE}, un prélèvement par carte de %{AMOUNT} était prévu le %{DATE}."
error: "Malheureusement, ce prélèvement n'a pas pu être effectué correctement."
action: "Veuillez vous rendre dans votre %{DASHBOARD} ou prendre contact avec un gestionnaire sous 24 heures, faute de quoi votre abonnement risque d'être interrompu."
action_html: "Veuillez vous rendre dans %{DASHBOARD} ou prendre contact avec un gestionnaire sous 24 heures, faute de quoi votre abonnement risque d'être interrompu."
your_dashboard: "votre tableau de bord"
notify_admin_payment_schedule_check_deadline:
subject: "Échéance d'encaissement"