1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-20 14:54:15 +01:00

Merge branch 'dev' for release 5.3.9

This commit is contained in:
Du Peng 2022-04-01 16:40:20 +02:00
commit e66a6adece
6 changed files with 117 additions and 82 deletions

View File

@ -1,10 +1,16 @@
# Changelog Fab-manager
## v5.3.9 2022 April 01
- Optimise sql query, avoid to N+1
- Fix a security issue: updated ansi-regex to 4.1.1 to fix [CVE-2021-3807](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3807)
- Fix a bug: unable to show payment modal for stripe
## v5.3.8 2022 March 29
- Updated the version of ruby to 2.6.9
- Fix a bug: unable to show payment schedules list if active PayZen
- Fix a bug: unable to set user's invoicing profile names and email if active address required in create user form
- Fix a security issue: updated ruby to 2.6.9 to fix [CVE-2021-31810](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31810), [CVE-2021-32066](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-32066) , [CVE-2021-31799](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41817), [CVE-2021-31799](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41817) and [CVE-2021-41819](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41819)
- [TODO DEPLOY] `rails fablab:fix:invoices_without_names_and_email`
## v5.3.7 2022 March 28
@ -28,7 +34,6 @@
- Removed unmaintained gem sidekiq-cron and replaced it with sidekiq-scheduler
- Removed unmaintained @rails/webpacker v5 and replaced it with shakapacker v6.2.0
- Removed dependency to auto-ngtemplate-loader
- Removed support for Universal Analytics
- Updated deprecated division operators in sass
- Fix a bug: prepaid-packs purchases are reported as subscriptions in the statistics
- Fix a bug: error Couldn't find the binary git during assets compilation

View File

@ -1,4 +1,4 @@
import React, { ReactEventHandler, useState } from 'react';
import React, { ReactEventHandler, useState, useEffect, ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { Loader } from '../base/loader';
import _ from 'lodash';
@ -11,6 +11,8 @@ import {
import FormatLib from '../../lib/format';
import { PaymentScheduleItemActions, TypeOnce } from './payment-schedule-item-actions';
import { StripeElements } from '../payment/stripe/stripe-elements';
import SettingAPI from '../../api/setting';
import { Setting, SettingName } from '../../models/setting';
interface PaymentSchedulesTableProps {
paymentSchedules: Array<PaymentSchedule>,
@ -35,6 +37,13 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
[TypeOnce.CardUpdate, new Map()],
[TypeOnce.UpdatePaymentMean, new Map()]
]));
const [gateway, setGateway] = useState<Setting>(null);
useEffect(() => {
SettingAPI.get(SettingName.PaymentGateway)
.then(setting => setGateway(setting))
.catch(error => onError(error));
}, []);
/**
* Check if the requested payment schedule is displayed with its deadlines (PaymentScheduleItem) or without them
@ -110,76 +119,98 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
refreshList();
};
return (
<div>
<StripeElements>
<table className="schedules-table">
<thead>
<tr>
<th className="w-35" />
<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={showCustomer ? 6 : 5}>
<table className="schedules-table-body">
<tbody>
<tr>
<td className="w-35 row-header" onClick={togglePaymentScheduleDetails(p.id)}>{expandCollapseIcon(p.id)}</td>
<td className="w-200">{p.reference}</td>
<td className="w-200">{FormatLib.date(_.minBy(p.items, 'due_date').due_date)}</td>
<td className="w-120">{FormatLib.price(p.total)}</td>
{showCustomer && <td className="w-200">{p.user.name}</td>}
<td className="w-200">{downloadScheduleButton(p.id)}</td>
</tr>
<tr style={{ display: statusDisplay(p.id) }}>
<td className="w-35" />
<td colSpan={showCustomer ? 5 : 4}>
<div>
<table className="schedule-items-table">
<thead>
<tr>
<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>
<tbody>
{_.orderBy(p.items, 'due_date').map(item => <tr key={item.id}>
<td>{FormatLib.date(item.due_date)}</td>
<td>{FormatLib.price(item.amount)}</td>
<td>{formatState(item, p)}</td>
<td>
<PaymentScheduleItemActions paymentScheduleItem={item}
paymentSchedule={p}
onError={onError}
onSuccess={refreshSchedulesTable}
onCardUpdateSuccess={onCardUpdateSuccess}
operator={operator}
displayOnceMap={displayOnceMap}
show={isExpanded(p.id)}/>
</td>
</tr>)}
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</td>
</tr>)}
</tbody>
</table>
</StripeElements>
</div>
);
const renderPaymentSchedulesTable = (): ReactElement => {
return (
<table className="schedules-table">
<thead>
<tr>
<th className="w-35" />
<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={showCustomer ? 6 : 5}>
<table className="schedules-table-body">
<tbody>
<tr>
<td className="w-35 row-header" onClick={togglePaymentScheduleDetails(p.id)}>{expandCollapseIcon(p.id)}</td>
<td className="w-200">{p.reference}</td>
<td className="w-200">{FormatLib.date(_.minBy(p.items, 'due_date').due_date)}</td>
<td className="w-120">{FormatLib.price(p.total)}</td>
{showCustomer && <td className="w-200">{p.user.name}</td>}
<td className="w-200">{downloadScheduleButton(p.id)}</td>
</tr>
<tr style={{ display: statusDisplay(p.id) }}>
<td className="w-35" />
<td colSpan={showCustomer ? 5 : 4}>
<div>
<table className="schedule-items-table">
<thead>
<tr>
<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>
<tbody>
{_.orderBy(p.items, 'due_date').map(item => <tr key={item.id}>
<td>{FormatLib.date(item.due_date)}</td>
<td>{FormatLib.price(item.amount)}</td>
<td>{formatState(item, p)}</td>
<td>
<PaymentScheduleItemActions paymentScheduleItem={item}
paymentSchedule={p}
onError={onError}
onSuccess={refreshSchedulesTable}
onCardUpdateSuccess={onCardUpdateSuccess}
operator={operator}
displayOnceMap={displayOnceMap}
show={isExpanded(p.id)}/>
</td>
</tr>)}
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</td>
</tr>)}
</tbody>
</table>
);
};
/**
* Determine which gateway is enabled and return the appropriate payment schedules
*/
if (gateway === null) return <div/>;
switch (gateway.value) {
case 'stripe':
return (
<StripeElements>
{renderPaymentSchedulesTable()}
</StripeElements>
);
case 'payzen':
return (
<div>
{renderPaymentSchedulesTable()}
</div>
);
case null:
default:
console.error(`[PaymentSchedulesTable] Unimplemented gateway: ${gateway.value}`);
return <div />;
}
};
PaymentSchedulesTableComponent.defaultProps = { showCustomer: false };

View File

@ -27,7 +27,6 @@ export const StripeElements: React.FC = memo(({ children }) => {
{stripe && <Elements stripe={stripe}>
{children}
</Elements>}
{!stripe && children}
</div>
);
});

View File

@ -103,14 +103,14 @@ class Availabilities::AvailabilitiesService
def availabilities(reservable, type, user)
if user.admin? || user.manager?
reservable.availabilities
.includes(:tags)
.includes(:tags, :plans)
.where('end_at > ? AND available_type = ?', 1.month.ago, type)
.where(lock: false)
else
end_at = @maximum_visibility[:other]
end_at = @maximum_visibility[:year] if subscription_year?(user)
reservable.availabilities
.includes(:tags)
.includes(:tags, :plans)
.where('end_at > ? AND end_at < ? AND available_type = ?', DateTime.current, end_at, type)
.where('availability_tags.tag_id' => user.tag_ids.concat([nil]))
.where(lock: false)
@ -127,14 +127,14 @@ class Availabilities::AvailabilitiesService
# who made the request?
# 1) an admin (he can see all availabilities of 1 month ago and future)
if @current_user.admin?
availabilities.includes(:tags, :slots, trainings: [:machines])
availabilities.includes(:tags, :slots, :plans, trainings: [:machines])
.where('availabilities.start_at > ?', 1.month.ago)
.where(lock: false)
# 2) an user (he cannot see availabilities further than 1 (or 3) months)
else
end_at = @maximum_visibility[:other]
end_at = @maximum_visibility[:year] if show_extended_slots?(user)
availabilities.includes(:tags, :slots, :availability_tags, trainings: [:machines])
availabilities.includes(:tags, :slots, :availability_tags, :plans, trainings: [:machines])
.where('availabilities.start_at > ? AND availabilities.start_at < ?', DateTime.current, end_at)
.where('availability_tags.tag_id' => user.tag_ids.concat([nil]))
.where(lock: false)

View File

@ -1,6 +1,6 @@
{
"name": "fab-manager",
"version": "5.3.8",
"version": "5.3.9",
"description": "Fab-manager is the FabLab management solution. It provides a comprehensive, web-based, open-source tool to simplify your administrative tasks and your marker's projects.",
"keywords": [
"fablab",

View File

@ -2121,9 +2121,9 @@ ansi-html-community@^0.0.8:
integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
ansi-regex@^5.0.0:
version "5.0.0"