mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
Merge branch 'product-store_order' into product-store
This commit is contained in:
commit
eebf2bcb43
@ -40,7 +40,7 @@ class API::ProductsController < API::ApiController
|
||||
|
||||
def destroy
|
||||
authorize @product
|
||||
@product.destroy
|
||||
ProductService.destroy(@product)
|
||||
head :no_content
|
||||
end
|
||||
|
||||
|
3
app/exceptions/cannot_delete_product_error.rb
Normal file
3
app/exceptions/cannot_delete_product_error.rb
Normal file
@ -0,0 +1,3 @@
|
||||
# Raised when delete a product if this product has used in order
|
||||
class CannotDeleteProductError < StandardError
|
||||
end
|
5
app/exceptions/cart/item_amount_error.rb
Normal file
5
app/exceptions/cart/item_amount_error.rb
Normal file
@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Raised when the item's amount != product's amount
|
||||
class Cart::ItemAmountError < StandardError
|
||||
end
|
5
app/exceptions/cart/quantity_min_error.rb
Normal file
5
app/exceptions/cart/quantity_min_error.rb
Normal file
@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Raised when the item's quantity < product's quantity min
|
||||
class Cart::QuantityMinError < StandardError
|
||||
end
|
@ -59,7 +59,7 @@ export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, re
|
||||
{...register(id as FieldPath<TFieldValues>, {
|
||||
...rules,
|
||||
valueAsDate: type === 'date',
|
||||
setValueAs: v => (v === null && nullable) ? null : (type === 'number' ? parseInt(v, 10) : v),
|
||||
setValueAs: v => (v === null && nullable) ? null : (type === 'number' ? parseFloat(v) : v),
|
||||
value: defaultValue as FieldPathValue<TFieldValues, FieldPath<TFieldValues>>,
|
||||
onChange: (e) => { handleChange(e); }
|
||||
})}
|
||||
|
@ -280,7 +280,7 @@ export const ProductForm: React.FC<ProductFormProps> = ({ product, title, onSucc
|
||||
<FormInput id="amount"
|
||||
type="number"
|
||||
register={register}
|
||||
rules={{ required: true, min: 0.01 }}
|
||||
rules={{ required: true, min: 0 }}
|
||||
step={0.01}
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.price')} />
|
||||
|
@ -79,12 +79,10 @@ export const ProductItem: React.FC<ProductItemProps> = ({ product, onEdit, onDel
|
||||
<span>{t('app.admin.store.product_item.stock.external')}</span>
|
||||
<p>{product.stock.external}</p>
|
||||
</div>
|
||||
{product.amount &&
|
||||
<div className='price'>
|
||||
<p>{FormatLib.price(product.amount)}</p>
|
||||
<span>/ {t('app.admin.store.product_item.unit')}</span>
|
||||
</div>
|
||||
}
|
||||
<div className='price'>
|
||||
<p>{FormatLib.price(product.amount || 0)}</p>
|
||||
<span>/ {t('app.admin.store.product_item.unit')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='actions'>
|
||||
<div className='manage'>
|
||||
|
@ -81,12 +81,10 @@ export const StoreProductItem: React.FC<StoreProductItemProps> = ({ product, car
|
||||
<img src={productImageUrl(product)} alt='' />
|
||||
</div>
|
||||
<p className="name">{product.name}</p>
|
||||
{product.amount &&
|
||||
<div className='price'>
|
||||
<p>{FormatLib.price(product.amount)}</p>
|
||||
<span>/ {t('app.public.store_product_item.unit')}</span>
|
||||
</div>
|
||||
}
|
||||
<div className='price'>
|
||||
<p>{FormatLib.price(product.amount || 0)}</p>
|
||||
<span>/ {t('app.public.store_product_item.unit')}</span>
|
||||
</div>
|
||||
<FabStateLabel status={statusColor(product)}>
|
||||
{productStockStatus(product)}
|
||||
</FabStateLabel>
|
||||
|
@ -180,7 +180,7 @@ export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, current
|
||||
{productStockStatus(product)}
|
||||
</FabStateLabel>
|
||||
<div className='price'>
|
||||
<p>{FormatLib.price(product.amount)} <sup>TTC</sup></p>
|
||||
<p>{FormatLib.price(product.amount || 0)} <sup>TTC</sup></p>
|
||||
<span>/ {t('app.public.store_product_item.unit')}</span>
|
||||
</div>
|
||||
{product.stock.external > (product.quantity_min || 1) &&
|
||||
|
@ -20,7 +20,8 @@ class Product < ApplicationRecord
|
||||
accepts_nested_attributes_for :product_stock_movements, allow_destroy: true, reject_if: :all_blank
|
||||
|
||||
validates :name, :slug, presence: true
|
||||
validates :amount, numericality: { greater_than: 0, allow_nil: true }
|
||||
validates :slug, uniqueness: true
|
||||
validates :amount, numericality: { greater_than_or_equal_to: 0, allow_nil: true }
|
||||
|
||||
scope :active, -> { where(is_active: true) }
|
||||
|
||||
|
@ -7,6 +7,7 @@ class ProductCategory < ApplicationRecord
|
||||
friendly_id :name, use: :slugged
|
||||
|
||||
validates :name, :slug, presence: true
|
||||
validates :slug, uniqueness: true
|
||||
|
||||
belongs_to :parent, class_name: 'ProductCategory'
|
||||
has_many :children, class_name: 'ProductCategory', foreign_key: :parent_id
|
||||
|
@ -11,7 +11,7 @@ class Cart::AddItemService
|
||||
quantity = orderable.quantity_min > quantity.to_i && item.nil? ? orderable.quantity_min : quantity.to_i
|
||||
|
||||
if item.nil?
|
||||
item = order.order_items.new(quantity: quantity, orderable: orderable, amount: orderable.amount)
|
||||
item = order.order_items.new(quantity: quantity, orderable: orderable, amount: orderable.amount || 0)
|
||||
else
|
||||
item.quantity += quantity.to_i
|
||||
end
|
||||
|
@ -7,9 +7,13 @@ class Checkout::PaymentService
|
||||
include Payments::PaymentConcern
|
||||
|
||||
def payment(order, operator, coupon_code, payment_id = '')
|
||||
raise Cart::InactiveProductError unless Orders::OrderService.new.all_products_is_active?(order)
|
||||
|
||||
raise Cart::OutStockError unless Orders::OrderService.new.in_stock?(order, 'external')
|
||||
|
||||
raise Cart::InactiveProductError unless Orders::OrderService.new.all_products_is_active?(order)
|
||||
raise Cart::QuantityMinError unless Orders::OrderService.new.greater_than_quantity_min?(order)
|
||||
|
||||
raise Cart::ItemAmountError unless Orders::OrderService.new.item_amount_not_equal?(order)
|
||||
|
||||
CouponService.new.validate(coupon_code, order.statistic_profile.user.id)
|
||||
|
||||
|
@ -58,6 +58,20 @@ class Orders::OrderService
|
||||
true
|
||||
end
|
||||
|
||||
def greater_than_quantity_min?(order)
|
||||
order.order_items.each do |item|
|
||||
return false if item.quantity < item.orderable.quantity_min
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def item_amount_not_equal?(order)
|
||||
order.order_items.each do |item|
|
||||
return false if item.amount != item.orderable.amount
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def all_products_is_active?(order)
|
||||
order.order_items.each do |item|
|
||||
return false unless item.orderable.is_active
|
||||
|
@ -55,7 +55,8 @@ class ProductService
|
||||
def create(product_params, stock_movement_params = [])
|
||||
product = Product.new(product_params)
|
||||
product.amount = amount_multiplied_by_hundred(product_params[:amount])
|
||||
update(product, product_params, stock_movement_params)
|
||||
update_stock(product, stock_movement_params)
|
||||
product
|
||||
end
|
||||
|
||||
def update(product, product_params, stock_movement_params = [])
|
||||
@ -64,5 +65,20 @@ class ProductService
|
||||
update_stock(product, stock_movement_params)
|
||||
product
|
||||
end
|
||||
|
||||
def destroy(product)
|
||||
used_in_order = OrderItem.joins(:order).where.not('orders.state' => 'cart')
|
||||
.exists?(orderable: product)
|
||||
raise CannotDeleteProductError if used_in_order
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
orders_with_product = Order.joins(:order_items).where(state: 'cart').where('order_items.orderable': product)
|
||||
orders_with_product.each do |order|
|
||||
::Cart::RemoveItemService.new.call(order, product)
|
||||
end
|
||||
|
||||
product.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user