mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
(feat) update the stock total
This commit is contained in:
parent
f705f71c4f
commit
feabded2a0
@ -18,8 +18,7 @@ class API::ProductsController < API::ApiController
|
||||
|
||||
def create
|
||||
authorize Product
|
||||
@product = Product.new(product_params)
|
||||
@product.amount = ProductService.amount_multiplied_by_hundred(@product.amount)
|
||||
@product = ProductService.create(product_params, params[:product][:product_stock_movements_attributes])
|
||||
if @product.save
|
||||
render status: :created
|
||||
else
|
||||
@ -30,9 +29,8 @@ class API::ProductsController < API::ApiController
|
||||
def update
|
||||
authorize @product
|
||||
|
||||
product_parameters = product_params
|
||||
product_parameters[:amount] = ProductService.amount_multiplied_by_hundred(product_parameters[:amount])
|
||||
if @product.update(product_parameters)
|
||||
@product = ProductService.update(@product, product_params, params[:product][:product_stock_movements_attributes])
|
||||
if @product.save
|
||||
render status: :ok
|
||||
else
|
||||
render json: @product.errors.full_messages, status: :unprocessable_entity
|
||||
@ -62,7 +60,6 @@ class API::ProductsController < API::ApiController
|
||||
:low_stock_alert, :low_stock_threshold,
|
||||
machine_ids: [],
|
||||
product_files_attributes: %i[id attachment _destroy],
|
||||
product_images_attributes: %i[id attachment is_main _destroy],
|
||||
product_stock_movements_attributes: %i[id quantity reason stock_type])
|
||||
product_images_attributes: %i[id attachment is_main _destroy])
|
||||
end
|
||||
end
|
||||
|
@ -38,12 +38,13 @@ export default class ProductLib {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the given quantity, prefixed by its addition operator (- or +)
|
||||
* Return the given quantity, prefixed by its addition operator (- or +), if needed
|
||||
*/
|
||||
static absoluteStockMovement = (quantity: number, reason: StockMovementReason): string => {
|
||||
if (ProductLib.stockMovementType(reason) === 'in') {
|
||||
return `+${quantity}`;
|
||||
} else {
|
||||
if (quantity < 0) return quantity.toString();
|
||||
return `-${quantity}`;
|
||||
}
|
||||
};
|
||||
|
@ -7,8 +7,8 @@ export interface ProductIndexFilter extends ApiFilter {
|
||||
|
||||
export type StockType = 'internal' | 'external' | 'all';
|
||||
|
||||
export const stockMovementInReasons = ['inward_stock', 'returned', 'cancelled', 'inventory_fix'] as const;
|
||||
export const stockMovementOutReasons = ['sold', 'missing', 'damaged'] as const;
|
||||
export const stockMovementInReasons = ['inward_stock', 'returned', 'cancelled', 'inventory_fix', 'other_in'] as const;
|
||||
export const stockMovementOutReasons = ['sold', 'missing', 'damaged', 'other_out'] as const;
|
||||
export const stockMovementAllReasons = [...stockMovementInReasons, ...stockMovementOutReasons] as const;
|
||||
|
||||
export type StockMovementReason = typeof stockMovementAllReasons[number];
|
||||
|
@ -8,7 +8,9 @@ class ProductStockMovement < ApplicationRecord
|
||||
ALL_STOCK_TYPES = %w[internal external].freeze
|
||||
enum stock_type: ALL_STOCK_TYPES.zip(ALL_STOCK_TYPES).to_h
|
||||
|
||||
ALL_REASONS = %w[inward_stock returned cancelled inventory_fix sold missing damaged].freeze
|
||||
INCOMING_REASONS = %w[inward_stock returned cancelled inventory_fix other_in].freeze
|
||||
OUTGOING_REASONS = %w[sold missing damaged other_out].freeze
|
||||
ALL_REASONS = [].concat(INCOMING_REASONS).concat(OUTGOING_REASONS).freeze
|
||||
enum reason: ALL_REASONS.zip(ALL_REASONS).to_h
|
||||
|
||||
validates :stock_type, presence: true
|
||||
@ -16,10 +18,4 @@ class ProductStockMovement < ApplicationRecord
|
||||
|
||||
validates :reason, presence: true
|
||||
validates :reason, inclusion: { in: ALL_REASONS }
|
||||
|
||||
before_create :set_date
|
||||
|
||||
def set_date
|
||||
self.date = DateTime.current
|
||||
end
|
||||
end
|
||||
|
@ -33,7 +33,8 @@ module Payments::PaymentConcern
|
||||
order.payment_gateway_object = PaymentGatewayObject.new(gateway_object_id: payment_id, gateway_object_type: payment_type)
|
||||
end
|
||||
order.order_items.each do |item|
|
||||
ProductService.update_stock(item.orderable, 'external', 'sold', -item.quantity, item.id)
|
||||
ProductService.update_stock(item.orderable,
|
||||
[{ stock_type: 'external', reason: 'sold', quantity: item.quantity, order_item_id: item.id }]).save
|
||||
end
|
||||
order.save
|
||||
order.reload
|
||||
|
@ -2,33 +2,54 @@
|
||||
|
||||
# Provides methods for Product
|
||||
class ProductService
|
||||
def self.list(filters)
|
||||
products = Product.includes(:product_images)
|
||||
if filters[:is_active].present?
|
||||
state = filters[:disabled] == 'false' ? [nil, false] : true
|
||||
products = products.where(is_active: state)
|
||||
class << self
|
||||
def list(filters)
|
||||
products = Product.includes(:product_images)
|
||||
if filters[:is_active].present?
|
||||
state = filters[:disabled] == 'false' ? [nil, false] : true
|
||||
products = products.where(is_active: state)
|
||||
end
|
||||
products
|
||||
end
|
||||
products
|
||||
end
|
||||
|
||||
# amount params multiplied by hundred
|
||||
def self.amount_multiplied_by_hundred(amount)
|
||||
if amount.present?
|
||||
v = amount.to_f
|
||||
# amount params multiplied by hundred
|
||||
def amount_multiplied_by_hundred(amount)
|
||||
if amount.present?
|
||||
v = amount.to_f
|
||||
|
||||
return nil if v.zero?
|
||||
return nil if v.zero?
|
||||
|
||||
return v * 100
|
||||
return v * 100
|
||||
end
|
||||
nil
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def self.update_stock(product, stock_type, reason, quantity, order_item_id = nil)
|
||||
remaining_stock = product.stock[stock_type] + quantity
|
||||
product.product_stock_movements.create(stock_type: stock_type, reason: reason, quantity: quantity, remaining_stock: remaining_stock,
|
||||
date: DateTime.current,
|
||||
order_item_id: order_item_id)
|
||||
product.stock[stock_type] = remaining_stock
|
||||
product.save
|
||||
# @param product Product
|
||||
# @param stock_movements [{stock_type: string, reason: string, quantity: number|string, order_item_id: number|nil}]
|
||||
def update_stock(product, stock_movements = nil)
|
||||
remaining_stock = { internal: product.stock['internal'], external: product.stock['external'] }
|
||||
product.product_stock_movements_attributes = stock_movements&.map do |movement|
|
||||
quantity = ProductStockMovement::OUTGOING_REASONS.include?(movement[:reason]) ? -movement[:quantity].to_i : movement[:quantity].to_i
|
||||
remaining_stock[movement[:stock_type].to_sym] += quantity
|
||||
{
|
||||
stock_type: movement[:stock_type], reason: movement[:reason], quantity: quantity,
|
||||
remaining_stock: remaining_stock[movement[:stock_type].to_sym], date: DateTime.current, order_item_id: movement[:order_item_id]
|
||||
}
|
||||
end || {}
|
||||
product.stock = remaining_stock
|
||||
product
|
||||
end
|
||||
|
||||
def create(product_params, stock_movement_params = [])
|
||||
product = Product.new(product_params)
|
||||
update(product, product_params, stock_movement_params)
|
||||
end
|
||||
|
||||
def update(product, product_params, stock_movement_params = [])
|
||||
product_params[:amount] = amount_multiplied_by_hundred(product_params[:amount])
|
||||
product.attributes = product_params
|
||||
update_stock(product, stock_movement_params)
|
||||
product
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2030,6 +2030,8 @@ en:
|
||||
sold: "Sold"
|
||||
missing: "Missing in stock"
|
||||
damaged: "Damaged product"
|
||||
other_in: "Other"
|
||||
other_out: "Other"
|
||||
orders:
|
||||
heading: "Orders"
|
||||
create_order: "Create an order"
|
||||
|
Loading…
x
Reference in New Issue
Block a user