1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-17 06:52:27 +01:00

(quality) compute withdrawal instructions server side

This commit is contained in:
Sylvain 2022-10-05 12:06:35 +02:00
parent 185b4f1459
commit 0464aae23e
13 changed files with 62 additions and 54 deletions

View File

@ -25,6 +25,17 @@ class API::OrdersController < API::ApiController
head :no_content
end
def withdrawal_instructions
begin
order = Order.find(params[:id])
rescue ActiveRecord::RecordNotFound
order = nil
end
authorize order || Order
render html: ::Orders::OrderService.withdrawal_instructions(order)
end
private
def set_order

View File

@ -18,4 +18,9 @@ export default class OrderAPI {
const res: AxiosResponse<Order> = await apiClient.patch(`/api/orders/${order.id}`, { order: { state, note } });
return res?.data;
}
static async withdrawalInstructions (order?: Order): Promise<string> {
const res: AxiosResponse<string> = await apiClient.get(`/api/orders/${order?.id}/withdrawal_instructions`);
return res?.data;
}
}

View File

@ -18,9 +18,8 @@ import noImage from '../../../../images/no_image.png';
import Switch from 'react-switch';
import OrderLib from '../../lib/order';
import { CaretDown, CaretUp } from 'phosphor-react';
import SettingAPI from '../../api/setting';
import { SettingName } from '../../models/setting';
import _ from 'lodash';
import OrderAPI from '../../api/order';
declare const Application: IApplication;
@ -41,11 +40,11 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
const [cartErrors, setCartErrors] = useState<OrderErrors>(null);
const [noMemberError, setNoMemberError] = useState<boolean>(false);
const [paymentModal, setPaymentModal] = useState<boolean>(false);
const [settings, setSettings] = useState<Map<SettingName, string>>(null);
const [withdrawalInstructions, setWithdrawalInstructions] = useState<string>(null);
useEffect(() => {
SettingAPI.query(['store_withdrawal_instructions', 'fablab_name'])
.then(res => setSettings(res))
OrderAPI.withdrawalInstructions(cart)
.then(setWithdrawalInstructions)
.catch(onError);
}, []);
@ -244,17 +243,6 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
}
};
/**
* Text instructions for the customer
*/
const withdrawalInstructions = (): string => {
const instructions = settings?.get('store_withdrawal_instructions');
if (!_.isEmpty(instructions)) {
return instructions;
}
return t('app.public.store_cart.please_contact_FABLAB', { FABLAB: settings?.get('fablab_name') });
};
return (
<div className='store-cart'>
<div className="store-cart-list">
@ -319,7 +307,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
<div className="group">
<div className='store-cart-info'>
<h3>{t('app.public.store_cart.pickup')}</h3>
<p dangerouslySetInnerHTML={{ __html: withdrawalInstructions() }} />
<p dangerouslySetInnerHTML={{ __html: withdrawalInstructions }} />
</div>
{cart && !cartIsEmpty() &&

View File

@ -50,13 +50,13 @@ export const OrderItem: React.FC<OrderItemProps> = ({ order, currentUser }) => {
<span>{t('app.shared.store.order_item.created_at')}</span>
<div>
<p>{FormatLib.date(order.created_at)}
<div className="fab-tooltip">
<span className="fab-tooltip">
<span className="trigger"><PlusCircle size={16} weight="light" /></span>
<div className="content">
<span className="content">
{t('app.shared.store.order_item.last_update')}<br />
{FormatLib.date(order.updated_at)}
</div>
</div>
</span>
</span>
</p>
</div>
</div>

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import _ from 'lodash';
import { IApplication } from '../../models/application';
import { User } from '../../models/user';
import { react2angular } from 'react2angular';
@ -12,8 +11,6 @@ import { Order } from '../../models/order';
import FormatLib from '../../lib/format';
import OrderLib from '../../lib/order';
import { OrderActions } from './order-actions';
import SettingAPI from '../../api/setting';
import { SettingName } from '../../models/setting';
declare const Application: IApplication;
@ -31,17 +28,20 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderId, currentUser, onSu
const { t } = useTranslation('shared');
const [order, setOrder] = useState<Order>();
const [settings, setSettings] = useState<Map<SettingName, string>>(null);
const [withdrawalInstructions, setWithdrawalInstructions] = useState<string>(null);
useEffect(() => {
OrderAPI.get(orderId).then(data => {
setOrder(data);
}).catch(onError);
SettingAPI.query(['store_withdrawal_instructions', 'fablab_name'])
.then(res => setSettings(res))
.catch(onError);
}, []);
useEffect(() => {
OrderAPI.withdrawalInstructions(order)
.then(setWithdrawalInstructions)
.catch(onError);
}, [order]);
/**
* Check if the current operator has administrative rights or is a normal member
*/
@ -79,17 +79,6 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderId, currentUser, onSu
return paymentVerbose;
};
/**
* Text instructions for the customer
*/
const withdrawalInstructions = (): string => {
const instructions = settings?.get('store_withdrawal_instructions');
if (!_.isEmpty(instructions)) {
return instructions;
}
return t('app.shared.store.show_order.please_contact_FABLAB', { FABLAB: settings?.get('fablab_name') });
};
/**
* Callback after action success
*/
@ -202,7 +191,7 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderId, currentUser, onSu
</div>
<div className="withdrawal-instructions">
<label>{t('app.shared.store.show_order.pickup')}</label>
<p dangerouslySetInnerHTML={{ __html: withdrawalInstructions() }} />
<p dangerouslySetInnerHTML={{ __html: withdrawalInstructions }} />
</div>
</div>
</div>

View File

@ -13,4 +13,8 @@ class OrderPolicy < ApplicationPolicy
def destroy?
user.privileged?
end
def withdrawal_instructions?
user.privileged? || (record&.statistic_profile_id == user.statistic_profile.id)
end
end

View File

@ -3,6 +3,8 @@
# Provides methods for Order
class Orders::OrderService
class << self
include ApplicationHelper
ORDERS_PER_PAGE = 20
def list(filters, current_user)
@ -71,6 +73,14 @@ class Orders::OrderService
true
end
def withdrawal_instructions(order)
res = order&.order_activities&.find_by(activity_type: 'ready')&.note.presence ||
Setting.get('store_withdrawal_instructions').presence ||
_t('order.please_contact_FABLAB', FABLAB: Setting.get('fablab_name').presence || 'empty')
ActionController::Base.helpers.sanitize(res, tags: %w[p ul li h3 u em strong a], attributes: %w[target rel href])
end
private
def filter_by_user(orders, filters, current_user)

View File

@ -4,5 +4,5 @@
<%= t('.body.notify_user_order_is_ready', REFERENCE: @attached_object.order.reference) %>
</p>
<p>
<%= sanitize @attached_object.note.presence || Setting.get('store_withdrawal_istructions').presence || _t('notify_user_order_is_ready.body.please_contact_FABLAB', FABLAB: Setting.get('fablab_name')) %>
<%= ::Orders::OrderService.withdrawal_instructions(@attached_object.order) %>
</p>

View File

@ -442,7 +442,6 @@ en:
checkout_error: "An unexpected error occurred. Please contact the administrator."
checkout_success: "Purchase confirmed. Thanks!"
select_user: "Please select a user before continuing."
please_contact_FABLAB: "Please contact {FABLAB, select, undefined{us} other{{FABLAB}}} for withdrawal instructions."
update_item: "Update"
errors:
product_not_found: "This product is no longer available, please remove it from your cart."

View File

@ -593,7 +593,6 @@ en:
coupon: "Coupon"
cart_total: "Cart total"
pickup: "Pickup your products"
please_contact_FABLAB: "Please contact {FABLAB, select, undefined{us} other{{FABLAB}}} for withdrawal instructions."
state:
cart: 'Cart'
in_progress: 'Under preparation'
@ -623,12 +622,12 @@ en:
delivered: "Delivered"
confirm: 'Confirm'
confirmation_required: "Confirmation required"
confirm_order_in_progress_html: "Please confirm this order in being prepared."
confirm_order_in_progress_html: "Please confirm that this order in being prepared."
order_in_progress_success: "Order is under preparation"
confirm_order_ready_html: "Please confirm this order is ready."
confirm_order_ready_html: "Please confirm that this order is ready."
order_ready_note: 'You can leave a message to the customer about withdrawal instructions'
order_ready_success: "Order is ready"
confirm_order_delivered_html: "Please confirm this order was delivered."
confirm_order_delivered_html: "Please confirm that this order was delivered."
order_delivered_success: "Order was delivered"
confirm_order_canceled_html: "<strong>Do you really want to cancel this order?</strong><p>If this impacts stock, please reflect the change in <em>edit product &gt; stock management</em>. This won't be automatic.</p>"
order_canceled_success: "Order was canceled"

View File

@ -44,8 +44,8 @@ en:
registration_disabled: "Registration is disabled"
undefined_in_store: "must be defined to make the product available in the store"
gateway_error: "Payement gateway error: %{MESSAGE}"
gateway_amount_too_small: "Payments under %{AMOUNT} are not supported. Please contact reception directly."
gateway_amount_too_large: "Payments above %{AMOUNT} are not supported. Please contact reception directly."
gateway_amount_too_small: "Payments under %{AMOUNT} are not supported. Please order directly at the reception."
gateway_amount_too_large: "Payments above %{AMOUNT} are not supported. Please order directly at the reception."
apipie:
api_documentation: "API Documentation"
code: "HTTP code"
@ -475,6 +475,8 @@ en:
free_extension: "Free extension of a subscription, until %{DATE}"
statistic_profile:
birthday_in_past: "The date of birth must be in the past"
order:
please_contact_FABLAB: "Please contact {FABLAB, select, nil{us} other{{FABLAB}}} for withdrawal instructions."
settings:
locked_setting: "the setting is locked."
about_title: "\"About\" page title"

View File

@ -378,12 +378,11 @@ en:
subject: "Your command is ready"
body:
notify_user_order_is_ready: "Your command %{REFERENCE} is ready:"
please_contact_FABLAB: "Please contact {FABLAB, select, undefined{us} other{{FABLAB}}} for withdrawal instructions."
notify_user_order_is_canceled:
subject: "Your command is canceled"
subject: "Your command was canceled"
body:
notify_user_order_is_canceled: "Your command %{REFERENCE} is canceled."
notify_user_order_is_canceled: "Your command %{REFERENCE} was canceled."
notify_user_order_is_refunded:
subject: "Your command is refunded"
subject: "Your command was refunded"
body:
notify_user_order_is_refunded: "Your command %{REFERENCE} is refunded:"
notify_user_order_is_refunded: "Your command %{REFERENCE} was refunded."

View File

@ -169,7 +169,9 @@ Rails.application.routes.draw do
post 'payment', on: :collection
post 'confirm_payment', on: :collection
end
resources :orders, except: %i[create]
resources :orders, except: %i[create] do
get 'withdrawal_instructions', on: :member
end
# for admin
resources :trainings do