mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-17 11:54:22 +01:00
Merge branch 'product-store-payment' into product-store
This commit is contained in:
commit
cd1bfe976c
@ -31,6 +31,12 @@ class API::CartController < API::ApiController
|
||||
render 'api/orders/show'
|
||||
end
|
||||
|
||||
def set_offer
|
||||
authorize @current_order, policy_class: CartPolicy
|
||||
@order = Cart::SetOfferService.new.call(@current_order, orderable, cart_params[:is_offered])
|
||||
render 'api/orders/show'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def orderable
|
||||
|
@ -3,7 +3,7 @@
|
||||
# API Controller for resources of type Coupon
|
||||
# Coupons are used in payments
|
||||
class API::CouponsController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :authenticate_user!, except: %i[validate]
|
||||
before_action :set_coupon, only: %i[show update destroy]
|
||||
|
||||
# Number of notifications added to the page when the user clicks on 'load next notifications'
|
||||
@ -31,18 +31,18 @@ class API::CouponsController < API::ApiController
|
||||
if @coupon.nil?
|
||||
render json: { status: 'rejected' }, status: :not_found
|
||||
else
|
||||
_user_id = if !current_user.admin?
|
||||
current_user.id
|
||||
else
|
||||
_user_id = if current_user&.admin?
|
||||
params[:user_id]
|
||||
else
|
||||
current_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
|
||||
else
|
||||
if status == 'active'
|
||||
render :validate, status: :ok, location: @coupon
|
||||
else
|
||||
render json: { status: status }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -17,6 +17,6 @@ module API::OrderConcern
|
||||
end
|
||||
|
||||
def cart_params
|
||||
params.permit(:order_token, :orderable_id, :quantity, :user_id)
|
||||
params.permit(:order_token, :orderable_id, :quantity, :user_id, :is_offered)
|
||||
end
|
||||
end
|
||||
|
@ -22,4 +22,9 @@ export default class CartAPI {
|
||||
const res: AxiosResponse<Order> = await apiClient.put('/api/cart/set_quantity', { order_token: order.token, orderable_id: orderableId, quantity });
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
static async setOffer (order: Order, orderableId: number, isOffered: boolean): Promise<Order> {
|
||||
const res: AxiosResponse<Order> = await apiClient.put('/api/cart/set_offer', { order_token: order.token, orderable_id: orderableId, is_offered: isOffered });
|
||||
return res?.data;
|
||||
}
|
||||
}
|
||||
|
@ -22,13 +22,15 @@ const CartButton: React.FC = () => {
|
||||
* Goto cart page
|
||||
*/
|
||||
const showCart = () => {
|
||||
window.location.href = '/#!/cart';
|
||||
window.location.href = '/#!/store/cart';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="cart-button" onClick={showCart}>
|
||||
<i className="fas fa-cart-arrow-down" />
|
||||
<span>{cart?.order_items_attributes?.length}</span>
|
||||
{cart && cart.order_items_attributes.length > 0 &&
|
||||
<span>{cart.order_items_attributes.length}</span>
|
||||
}
|
||||
<p>{t('app.public.cart_button.my_cart')}</p>
|
||||
</div>
|
||||
);
|
||||
|
@ -115,8 +115,12 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
/**
|
||||
* Toggle product offer
|
||||
*/
|
||||
const onSwitch = (product, checked: boolean) => {
|
||||
console.log('Offer ', product.orderable_name, ': ', checked);
|
||||
const toogleProductOffer = (item) => {
|
||||
return (checked: boolean) => {
|
||||
CartAPI.setOffer(cart, item.orderable_id, checked).then(data => {
|
||||
setCart(data);
|
||||
}).catch(onError);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -128,14 +132,50 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the item total
|
||||
*/
|
||||
const itemAmount = (item): number => {
|
||||
return item.quantity * Math.trunc(item.amount * 100) / 100;
|
||||
};
|
||||
|
||||
/**
|
||||
* return true if cart has offered item
|
||||
*/
|
||||
const hasOfferedItem = (): boolean => {
|
||||
return cart.order_items_attributes
|
||||
.filter(i => i.is_offered).length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the offered item total
|
||||
*/
|
||||
const offeredAmount = (): number => {
|
||||
return cart.order_items_attributes
|
||||
.filter(i => i.is_offered)
|
||||
.map(i => i.amount)
|
||||
.reduce((acc, curr) => acc + curr, 0);
|
||||
.map(i => Math.trunc(i.amount * 100) * i.quantity)
|
||||
.reduce((acc, curr) => acc + curr, 0) / 100;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the total amount before offered amount
|
||||
*/
|
||||
const totalBeforeOfferedAmount = (): number => {
|
||||
return (Math.trunc(cart.total * 100) + Math.trunc(offeredAmount() * 100)) / 100;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the coupon amount
|
||||
*/
|
||||
const couponAmount = (): number => {
|
||||
return (Math.trunc(cart.total * 100) - Math.trunc(computePriceWithCoupon(cart.total, cart.coupon) * 100)) / 100.00;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the paid total amount
|
||||
*/
|
||||
const paidTotal = (): number => {
|
||||
return computePriceWithCoupon(cart.total, cart.coupon);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -163,7 +203,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
</select>
|
||||
<div className='total'>
|
||||
<span>{t('app.public.store_cart.total')}</span>
|
||||
<p>{FormatLib.price(item.quantity * item.amount)}</p>
|
||||
<p>{FormatLib.price(itemAmount(item))}</p>
|
||||
</div>
|
||||
<FabButton className="main-action-btn" onClick={removeProductFromCart(item)}>
|
||||
<i className="fa fa-trash" />
|
||||
@ -175,7 +215,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
<span>Offer the product</span>
|
||||
<Switch
|
||||
checked={item.is_offered}
|
||||
onChange={(checked) => onSwitch(item, checked)}
|
||||
onChange={toogleProductOffer(item)}
|
||||
width={40}
|
||||
height={19}
|
||||
uncheckedIcon={false}
|
||||
@ -194,7 +234,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
<p>[TODO: texte venant des paramètres de la boutique…]</p>
|
||||
</div>
|
||||
|
||||
{cart && !cartIsEmpty() && cart.user &&
|
||||
{cart && !cartIsEmpty() &&
|
||||
<div className='store-cart-coupon'>
|
||||
<CouponInput user={cart.user as User} amount={cart.total} onChange={applyCoupon} />
|
||||
</div>
|
||||
@ -203,7 +243,7 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
|
||||
<aside>
|
||||
{cart && !cartIsEmpty() && isPrivileged() &&
|
||||
<div> <MemberSelect onSelected={handleChangeMember} /></div>
|
||||
<div> <MemberSelect onSelected={handleChangeMember} defaultUser={cart.user as User} /></div>
|
||||
}
|
||||
|
||||
{cart && !cartIsEmpty() && <>
|
||||
@ -211,17 +251,17 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
<h3>{t('app.public.store_cart.checkout_header')}</h3>
|
||||
<span>{t('app.public.store_cart.checkout_products_COUNT', { COUNT: cart?.order_items_attributes.length })}</span>
|
||||
<div className="list">
|
||||
<p>{t('app.public.store_cart.checkout_products_total')} <span>{FormatLib.price(cart.total)}</span></p>
|
||||
{offeredAmount() > 0 &&
|
||||
<p>{t('app.public.store_cart.checkout_products_total')} <span>{FormatLib.price(totalBeforeOfferedAmount())}</span></p>
|
||||
{hasOfferedItem() &&
|
||||
<p className='gift'>{t('app.public.store_cart.checkout_gift_total')} <span>-{FormatLib.price(offeredAmount())}</span></p>
|
||||
}
|
||||
{cart.coupon && computePriceWithCoupon(cart.total, cart.coupon) !== cart.total &&
|
||||
<p>{t('app.public.store_cart.checkout_coupon')} <span>{FormatLib.price(-(cart.total - computePriceWithCoupon(cart.total, cart.coupon)))}</span></p>
|
||||
{cart.coupon &&
|
||||
<p>{t('app.public.store_cart.checkout_coupon')} <span>-{FormatLib.price(couponAmount())}</span></p>
|
||||
}
|
||||
</div>
|
||||
<p className='total'>{t('app.public.store_cart.checkout_total')} <span>{FormatLib.price(computePriceWithCoupon(cart.total, cart.coupon))}</span></p>
|
||||
<p className='total'>{t('app.public.store_cart.checkout_total')} <span>{FormatLib.price(paidTotal())}</span></p>
|
||||
</div>
|
||||
<FabButton className='checkout-btn' onClick={checkout}>
|
||||
<FabButton className='checkout-btn' onClick={checkout} disabled={!cart.user}>
|
||||
{t('app.public.store_cart.checkout')}
|
||||
</FabButton>
|
||||
</>}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FabInput } from '../base/fab-input';
|
||||
import { FabAlert } from '../base/fab-alert';
|
||||
@ -27,6 +27,19 @@ export const CouponInput: React.FC<CouponInputProps> = ({ user, amount, onChange
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<boolean>(false);
|
||||
const [coupon, setCoupon] = useState<Coupon>();
|
||||
const [code, setCode] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
if (user && code) {
|
||||
handleChange(code);
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
if (code) {
|
||||
handleChange(code);
|
||||
}
|
||||
}, [amount]);
|
||||
|
||||
/**
|
||||
* callback for validate the code
|
||||
@ -36,6 +49,7 @@ export const CouponInput: React.FC<CouponInputProps> = ({ user, amount, onChange
|
||||
setMessages([]);
|
||||
setError(false);
|
||||
setCoupon(null);
|
||||
setCode(value);
|
||||
if (value) {
|
||||
setLoading(true);
|
||||
CouponAPI.validate(value, amount, user?.id).then((res) => {
|
||||
|
@ -12,13 +12,14 @@ import noImage from '../../../../images/no_image.png';
|
||||
interface StoreProductItemProps {
|
||||
product: Product,
|
||||
cart: Order,
|
||||
onSuccessAddProductToCart: (cart: Order) => void
|
||||
onSuccessAddProductToCart: (cart: Order) => void,
|
||||
onError: (message: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* This component shows a product item in store
|
||||
*/
|
||||
export const StoreProductItem: React.FC<StoreProductItemProps> = ({ product, cart, onSuccessAddProductToCart }) => {
|
||||
export const StoreProductItem: React.FC<StoreProductItemProps> = ({ product, cart, onSuccessAddProductToCart, onError }) => {
|
||||
const { t } = useTranslation('public');
|
||||
|
||||
/**
|
||||
@ -38,7 +39,7 @@ export const StoreProductItem: React.FC<StoreProductItemProps> = ({ product, car
|
||||
const addProductToCart = (e: React.BaseSyntheticEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
CartAPI.addItem(cart, product.id, 1).then(onSuccessAddProductToCart);
|
||||
CartAPI.addItem(cart, product.id, 1).then(onSuccessAddProductToCart).catch(onError);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -7,9 +7,12 @@ import { Loader } from '../base/loader';
|
||||
import { IApplication } from '../../models/application';
|
||||
import _ from 'lodash';
|
||||
import { Product } from '../../models/product';
|
||||
import { User } from '../../models/user';
|
||||
import ProductAPI from '../../api/product';
|
||||
import CartAPI from '../../api/cart';
|
||||
import noImage from '../../../../images/no_image.png';
|
||||
import { FabButton } from '../base/fab-button';
|
||||
import useCart from '../../hooks/use-cart';
|
||||
import { FilePdf, Minus, Plus } from 'phosphor-react';
|
||||
import { FabStateLabel } from '../base/fab-state-label';
|
||||
|
||||
@ -17,15 +20,18 @@ declare const Application: IApplication;
|
||||
|
||||
interface StoreProductProps {
|
||||
productSlug: string,
|
||||
onSuccess: (message: string) => void,
|
||||
onError: (message: string) => void,
|
||||
currentUser?: User
|
||||
}
|
||||
|
||||
/**
|
||||
* This component shows a product
|
||||
*/
|
||||
export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, onError }) => {
|
||||
export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, currentUser, onSuccess, onError }) => {
|
||||
const { t } = useTranslation('public');
|
||||
|
||||
const { cart, setCart } = useCart(currentUser);
|
||||
const [product, setProduct] = useState<Product>();
|
||||
const [showImage, setShowImage] = useState<number>(null);
|
||||
const [toCartCount, setToCartCount] = useState<number>(0);
|
||||
@ -37,11 +43,13 @@ export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, onError
|
||||
ProductAPI.get(productSlug).then(data => {
|
||||
setProduct(data);
|
||||
const productImage = _.find(data.product_images_attributes, { is_main: true });
|
||||
setShowImage(productImage.id);
|
||||
if (productImage) {
|
||||
setShowImage(productImage.id);
|
||||
}
|
||||
setToCartCount(data.quantity_min ? data.quantity_min : 1);
|
||||
setDisplayToggle(descContainer.current.offsetHeight < descContainer.current.scrollHeight);
|
||||
}).catch(() => {
|
||||
onError(t('app.public.store_product.unexpected_error_occurred'));
|
||||
}).catch((e) => {
|
||||
onError(t('app.public.store_product.unexpected_error_occurred') + e);
|
||||
});
|
||||
}, []);
|
||||
|
||||
@ -108,7 +116,10 @@ export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, onError
|
||||
* Add product to cart
|
||||
*/
|
||||
const addToCart = () => {
|
||||
console.log('Add', toCartCount, 'to cart');
|
||||
CartAPI.addItem(cart, product.id, toCartCount).then(data => {
|
||||
setCart(data);
|
||||
onSuccess(t('app.public.store.add_to_cart_success'));
|
||||
}).catch(onError);
|
||||
};
|
||||
|
||||
if (product) {
|
||||
@ -188,12 +199,12 @@ export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, onError
|
||||
return null;
|
||||
};
|
||||
|
||||
const StoreProductWrapper: React.FC<StoreProductProps> = ({ productSlug, onError }) => {
|
||||
const StoreProductWrapper: React.FC<StoreProductProps> = (props) => {
|
||||
return (
|
||||
<Loader>
|
||||
<StoreProduct productSlug={productSlug} onError={onError} />
|
||||
<StoreProduct {...props} />
|
||||
</Loader>
|
||||
);
|
||||
};
|
||||
|
||||
Application.Components.component('storeProduct', react2angular(StoreProductWrapper, ['productSlug', 'onError']));
|
||||
Application.Components.component('storeProduct', react2angular(StoreProductWrapper, ['productSlug', 'currentUser', 'onSuccess', 'onError']));
|
||||
|
@ -11,7 +11,6 @@ import ProductCategoryAPI from '../../api/product-category';
|
||||
import MachineAPI from '../../api/machine';
|
||||
import { StoreProductItem } from './store-product-item';
|
||||
import useCart from '../../hooks/use-cart';
|
||||
import { emitCustomEvent } from 'react-custom-events';
|
||||
import { User } from '../../models/user';
|
||||
import { Order } from '../../models/order';
|
||||
import { AccordionItem } from './accordion-item';
|
||||
@ -67,10 +66,6 @@ const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
emitCustomEvent('CartUpdate', cart);
|
||||
}, [cart]);
|
||||
|
||||
/**
|
||||
* Create categories tree (parent/children)
|
||||
*/
|
||||
@ -234,7 +229,7 @@ const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
|
||||
/>
|
||||
<div className="products-grid">
|
||||
{products.map((product) => (
|
||||
<StoreProductItem key={product.id} product={product} cart={cart} onSuccessAddProductToCart={addToCart} />
|
||||
<StoreProductItem key={product.id} product={product} cart={cart} onSuccessAddProductToCart={addToCart} onError={onError} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,6 +29,12 @@ export const MemberSelect: React.FC<MemberSelectProps> = ({ defaultUser, onSelec
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!defaultUser && value) {
|
||||
onSelected(value.value);
|
||||
}
|
||||
}, [defaultUser]);
|
||||
|
||||
/**
|
||||
* search members by name
|
||||
*/
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { emitCustomEvent } from 'react-custom-events';
|
||||
import { Order } from '../models/order';
|
||||
import CartAPI from '../api/cart';
|
||||
import { getCartToken, setCartToken } from '../lib/cart-token';
|
||||
@ -13,7 +14,7 @@ export default function useCart (user?: User) {
|
||||
async function createCart () {
|
||||
const currentCartToken = getCartToken();
|
||||
const data = await CartAPI.create(currentCartToken);
|
||||
setCart(data);
|
||||
_setCart(data);
|
||||
setLoading(false);
|
||||
setCartToken(data.token);
|
||||
}
|
||||
@ -30,15 +31,20 @@ export default function useCart (user?: User) {
|
||||
setLoading(true);
|
||||
const currentCartToken = getCartToken();
|
||||
const data = await CartAPI.create(currentCartToken);
|
||||
setCart(data);
|
||||
_setCart(data);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (user && cart && (!cart.statistic_profile_id || !cart.operator_id)) {
|
||||
if (user && cart && (!cart.statistic_profile_id || !cart.operator_profile_id)) {
|
||||
reloadCart();
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
return { loading, cart, error, setCart, reloadCart };
|
||||
const _setCart = (data: Order) => {
|
||||
setCart(data);
|
||||
emitCustomEvent('CartUpdate', data);
|
||||
};
|
||||
|
||||
return { loading, cart, error, setCart: _setCart, reloadCart };
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ export const computePriceWithCoupon = (price: number, coupon?: Coupon): number =
|
||||
return price;
|
||||
}
|
||||
if (coupon.type === 'percent_off') {
|
||||
return price - (price * coupon.percent_off / 100.00);
|
||||
return (Math.trunc(price * 100) - (Math.trunc(price * 100) * coupon.percent_off / 100)) / 100;
|
||||
} else if (coupon.type === 'amount_off' && price > coupon.amount_off) {
|
||||
return price - coupon.amount_off;
|
||||
return (Math.trunc(price * 100) - Math.trunc(coupon.amount_off * 100)) / 100;
|
||||
}
|
||||
return price;
|
||||
};
|
||||
|
@ -643,8 +643,8 @@ angular.module('application.router', ['ui.router'])
|
||||
})
|
||||
|
||||
// cart
|
||||
.state('app.public.cart', {
|
||||
url: '/cart',
|
||||
.state('app.public.store_cart', {
|
||||
url: '/store/cart',
|
||||
views: {
|
||||
'main@': {
|
||||
templateUrl: '/cart/index.html',
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="header-page">
|
||||
<div class="back">
|
||||
<a ng-click="backPrevLocation($event)"><i class="fas fa-long-arrow-alt-left "></i></a>
|
||||
<a ui-sref="app.public.store"><i class="fas fa-long-arrow-alt-left "></i></a>
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
|
@ -13,5 +13,5 @@
|
||||
</div>
|
||||
|
||||
<section class="m-lg">
|
||||
<store-product product-slug="productSlug" on-error="onError" on-success="onSuccess" />
|
||||
<store-product product-slug="productSlug" current-user="currentUser" on-error="onError" on-success="onSuccess" />
|
||||
</section>
|
||||
|
@ -13,4 +13,8 @@ class CartPolicy < ApplicationPolicy
|
||||
record.statistic_profile_id.nil? && record.operator_profile_id.nil?
|
||||
end
|
||||
end
|
||||
|
||||
def set_offer?
|
||||
user.privileged?
|
||||
end
|
||||
end
|
||||
|
@ -15,7 +15,7 @@ class Cart::AddItemService
|
||||
else
|
||||
item.quantity += quantity.to_i
|
||||
end
|
||||
order.total += (orderable.amount * quantity.to_i)
|
||||
order.total += (item.amount * quantity.to_i)
|
||||
ActiveRecord::Base.transaction do
|
||||
item.save
|
||||
order.save
|
||||
|
@ -7,7 +7,7 @@ class Cart::RemoveItemService
|
||||
|
||||
raise ActiveRecord::RecordNotFound if item.nil?
|
||||
|
||||
order.total -= (item.amount * item.quantity.to_i)
|
||||
order.total -= (item.amount * item.quantity.to_i) unless item.is_offered
|
||||
ActiveRecord::Base.transaction do
|
||||
item.destroy!
|
||||
order.save
|
||||
|
22
app/services/cart/set_offer_service.rb
Normal file
22
app/services/cart/set_offer_service.rb
Normal file
@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides methods for set offer to item in cart
|
||||
class Cart::SetOfferService
|
||||
def call(order, orderable, is_offered)
|
||||
item = order.order_items.find_by(orderable: orderable)
|
||||
|
||||
raise ActiveRecord::RecordNotFound if item.nil?
|
||||
|
||||
if !item.is_offered && is_offered
|
||||
order.total -= (item.amount * item.quantity)
|
||||
elsif item.is_offered && !is_offered
|
||||
order.total += (item.amount * item.quantity)
|
||||
end
|
||||
item.is_offered = is_offered
|
||||
ActiveRecord::Base.transaction do
|
||||
item.save
|
||||
order.save
|
||||
end
|
||||
order.reload
|
||||
end
|
||||
end
|
@ -12,7 +12,7 @@ class Cart::SetQuantityService
|
||||
raise ActiveRecord::RecordNotFound if item.nil?
|
||||
|
||||
different_quantity = quantity.to_i - item.quantity
|
||||
order.total += (orderable.amount * different_quantity)
|
||||
order.total += (item.amount * different_quantity) unless item.is_offered
|
||||
ActiveRecord::Base.transaction do
|
||||
item.update(quantity: quantity.to_i)
|
||||
order.save
|
||||
|
@ -11,7 +11,7 @@ class Checkout::PaymentService
|
||||
|
||||
raise Cart::InactiveProductError unless Orders::OrderService.new.all_products_is_active?(order)
|
||||
|
||||
CouponService.new.validate(coupon_code, order.statistic_profile.user)
|
||||
CouponService.new.validate(coupon_code, order.statistic_profile.user.id)
|
||||
|
||||
amount = debit_amount(order)
|
||||
if operator.privileged? || amount.zero?
|
||||
|
@ -10,7 +10,7 @@ module Payments::PaymentConcern
|
||||
end
|
||||
|
||||
def debit_amount(order, coupon_code = nil)
|
||||
total = CouponService.new.apply(order.total, coupon_code, order.statistic_profile.user)
|
||||
total = CouponService.new.apply(order.total, coupon_code, order.statistic_profile.user.id)
|
||||
wallet_debit = get_wallet_debit(order.statistic_profile.user, total)
|
||||
total - wallet_debit
|
||||
end
|
||||
|
@ -10,7 +10,7 @@ if order&.statistic_profile&.user
|
||||
end
|
||||
end
|
||||
|
||||
json.order_items_attributes order.order_items do |item|
|
||||
json.order_items_attributes order.order_items.order(created_at: :asc) do |item|
|
||||
json.id item.id
|
||||
json.orderable_type item.orderable_type
|
||||
json.orderable_id item.orderable_id
|
||||
|
@ -159,6 +159,7 @@ Rails.application.routes.draw do
|
||||
put 'add_item', on: :collection
|
||||
put 'remove_item', on: :collection
|
||||
put 'set_quantity', on: :collection
|
||||
put 'set_offer', on: :collection
|
||||
end
|
||||
resources :checkout, only: %i[] do
|
||||
post 'payment', on: :collection
|
||||
|
Loading…
x
Reference in New Issue
Block a user