1
0
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:
Sylvain 2022-09-13 15:01:55 +02:00
parent f705f71c4f
commit feabded2a0
7 changed files with 58 additions and 40 deletions

View File

@ -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

View File

@ -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}`;
}
};

View File

@ -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];

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"