mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Merge branch 'dev/gio' into 'feat/BE/Sprint-6'
[FEAT/BE][US#286/TASK#296,297] : Adjust Schema Database table product_warehouse, product and stock_logs; create sub module inventory product_stock and api list and get one See merge request mbugroup/lti-api!77
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE products
|
||||||
|
DROP COLUMN IF EXISTS is_visible;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE products
|
||||||
|
ADD COLUMN IF NOT EXISTS is_visible BOOLEAN NOT NULL DEFAULT TRUE;
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- Drop new indexes and FK
|
||||||
|
DROP INDEX IF EXISTS idx_product_warehouses_project_flock_kandang_id;
|
||||||
|
DROP INDEX IF EXISTS idx_product_warehouses_unique;
|
||||||
|
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
DROP CONSTRAINT IF EXISTS fk_product_warehouses_project_flock_kandang_id,
|
||||||
|
ALTER COLUMN project_flock_kandang_id DROP NOT NULL,
|
||||||
|
DROP COLUMN IF EXISTS project_flock_kandang_id;
|
||||||
|
|
||||||
|
-- Revert qty to integer quantity
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
RENAME COLUMN qty TO quantity;
|
||||||
|
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
ALTER COLUMN quantity TYPE INTEGER USING quantity::integer,
|
||||||
|
ALTER COLUMN quantity SET DEFAULT 0,
|
||||||
|
ALTER COLUMN quantity SET NOT NULL;
|
||||||
|
|
||||||
|
-- Restore audit/soft-delete columns
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
ADD COLUMN IF NOT EXISTS created_by BIGINT NOT NULL REFERENCES users (id),
|
||||||
|
ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
||||||
|
|
||||||
|
-- Recreate prior indexes
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_product_warehouses_deleted_at ON product_warehouses (deleted_at);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_product_warehouses_unique
|
||||||
|
ON product_warehouses (product_id, warehouse_id)
|
||||||
|
WHERE deleted_at IS NULL;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- Drop indexes that depend on deleted_at or old uniqueness
|
||||||
|
DROP INDEX IF EXISTS idx_product_warehouses_deleted_at;
|
||||||
|
DROP INDEX IF EXISTS idx_product_warehouses_unique;
|
||||||
|
|
||||||
|
-- Add new relation and adjust quantity column
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
ADD COLUMN IF NOT EXISTS project_flock_kandang_id BIGINT;
|
||||||
|
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
RENAME COLUMN quantity TO qty;
|
||||||
|
|
||||||
|
-- Enforce numeric quantity with precision and default
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
ALTER COLUMN qty TYPE NUMERIC(15, 3) USING qty::numeric(15, 3),
|
||||||
|
ALTER COLUMN qty SET DEFAULT 0,
|
||||||
|
ALTER COLUMN qty SET NOT NULL;
|
||||||
|
|
||||||
|
-- Remove audit/soft-delete columns no longer used
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
DROP COLUMN IF EXISTS created_by,
|
||||||
|
DROP COLUMN IF EXISTS created_at,
|
||||||
|
DROP COLUMN IF EXISTS updated_at,
|
||||||
|
DROP COLUMN IF EXISTS deleted_at;
|
||||||
|
|
||||||
|
-- Enforce FK and not-null for project_flock_kandang_id
|
||||||
|
ALTER TABLE product_warehouses
|
||||||
|
ADD CONSTRAINT fk_product_warehouses_project_flock_kandang_id
|
||||||
|
FOREIGN KEY (project_flock_kandang_id)
|
||||||
|
REFERENCES project_flock_kandangs (id)
|
||||||
|
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- New indexes
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_product_warehouses_project_flock_kandang_id
|
||||||
|
ON product_warehouses (project_flock_kandang_id);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_product_warehouses_unique
|
||||||
|
ON product_warehouses (product_id, warehouse_id, project_flock_kandang_id);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- Drop new indexes
|
||||||
|
DROP INDEX IF EXISTS stock_logs_loggable_type_loggable_id_idx;
|
||||||
|
DROP INDEX IF EXISTS stock_logs_product_warehouse_id_idx;
|
||||||
|
DROP INDEX IF EXISTS stock_logs_created_by_idx;
|
||||||
|
DROP INDEX IF EXISTS stock_logs_created_at_idx;
|
||||||
|
|
||||||
|
-- Restore obsolete columns
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
ADD COLUMN IF NOT EXISTS transaction_type VARCHAR(20) DEFAULT '' NOT NULL,
|
||||||
|
ADD COLUMN IF NOT EXISTS quantity NUMERIC(15, 3) DEFAULT 0 NOT NULL,
|
||||||
|
ADD COLUMN IF NOT EXISTS before_quantity NUMERIC(15, 3) DEFAULT 0 NOT NULL,
|
||||||
|
ADD COLUMN IF NOT EXISTS after_quantity NUMERIC(15, 3) DEFAULT 0 NOT NULL,
|
||||||
|
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
||||||
|
|
||||||
|
-- Rename columns back
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
RENAME COLUMN loggable_type TO log_type;
|
||||||
|
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
RENAME COLUMN loggable_id TO log_id;
|
||||||
|
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
RENAME COLUMN notes TO note;
|
||||||
|
|
||||||
|
-- Drop new columns
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
DROP COLUMN IF EXISTS increase,
|
||||||
|
DROP COLUMN IF EXISTS decrease;
|
||||||
|
|
||||||
|
-- Restore indexes for old structure
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_product_warehouse_id_idx ON stock_logs (product_warehouse_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_log_type_log_id_idx ON stock_logs (log_type, log_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_created_by_idx ON stock_logs (created_by);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_created_at_idx ON stock_logs (created_at);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_deleted_at_idx ON stock_logs (deleted_at);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- Drop old indexes tied to removed columns
|
||||||
|
DROP INDEX IF EXISTS stock_logs_log_type_log_id_idx;
|
||||||
|
DROP INDEX IF EXISTS stock_logs_deleted_at_idx;
|
||||||
|
|
||||||
|
-- Rename columns to new naming
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
RENAME COLUMN log_type TO loggable_type;
|
||||||
|
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
RENAME COLUMN log_id TO loggable_id;
|
||||||
|
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
RENAME COLUMN note TO notes;
|
||||||
|
|
||||||
|
-- Add new increase/decrease columns
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
ADD COLUMN IF NOT EXISTS increase NUMERIC(15, 3) DEFAULT 0,
|
||||||
|
ADD COLUMN IF NOT EXISTS decrease NUMERIC(15, 3) DEFAULT 0;
|
||||||
|
|
||||||
|
-- Adjust column definitions
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
ALTER COLUMN loggable_type TYPE VARCHAR(50),
|
||||||
|
ALTER COLUMN loggable_type SET NOT NULL,
|
||||||
|
ALTER COLUMN loggable_id SET NOT NULL,
|
||||||
|
ALTER COLUMN increase SET DEFAULT 0,
|
||||||
|
ALTER COLUMN increase SET NOT NULL,
|
||||||
|
ALTER COLUMN decrease SET DEFAULT 0,
|
||||||
|
ALTER COLUMN decrease SET NOT NULL;
|
||||||
|
|
||||||
|
-- Remove obsolete columns
|
||||||
|
ALTER TABLE stock_logs
|
||||||
|
DROP COLUMN IF EXISTS transaction_type,
|
||||||
|
DROP COLUMN IF EXISTS quantity,
|
||||||
|
DROP COLUMN IF EXISTS before_quantity,
|
||||||
|
DROP COLUMN IF EXISTS after_quantity,
|
||||||
|
DROP COLUMN IF EXISTS updated_at,
|
||||||
|
DROP COLUMN IF EXISTS deleted_at;
|
||||||
|
|
||||||
|
-- Recreate indexes for new structure
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_product_warehouse_id_idx ON stock_logs (product_warehouse_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_loggable_type_loggable_id_idx ON stock_logs (loggable_type, loggable_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_created_by_idx ON stock_logs (created_by);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS stock_logs_created_at_idx ON stock_logs (created_at);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -910,7 +910,7 @@ func seedProductWarehouse(tx *gorm.DB, createdBy uint) error {
|
|||||||
ProductId: product.Id,
|
ProductId: product.Id,
|
||||||
WarehouseId: warehouse.Id,
|
WarehouseId: warehouse.Id,
|
||||||
Quantity: seed.Quantity,
|
Quantity: seed.Quantity,
|
||||||
CreatedBy: createdBy,
|
// CreatedBy: createdBy,
|
||||||
}
|
}
|
||||||
if err := tx.Create(&productWarehouse).Error; err != nil {
|
if err := tx.Create(&productWarehouse).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ type Product struct {
|
|||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
IsVisible bool `gorm:"column:is_visible;default:true"`
|
||||||
|
|
||||||
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
||||||
Uom Uom `gorm:"foreignKey:UomId;references:Id"`
|
Uom Uom `gorm:"foreignKey:UomId;references:Id"`
|
||||||
ProductCategory ProductCategory `gorm:"foreignKey:ProductCategoryId;references:Id"`
|
ProductCategory ProductCategory `gorm:"foreignKey:ProductCategoryId;references:Id"`
|
||||||
ProductSuppliers []ProductSupplier `gorm:"foreignKey:ProductId;references:Id"`
|
ProductSuppliers []ProductSupplier `gorm:"foreignKey:ProductId;references:Id"`
|
||||||
Flags []Flag `gorm:"polymorphic:Flagable;polymorphicValue:products"`
|
Flags []Flag `gorm:"polymorphic:Flagable;polymorphicValue:products"`
|
||||||
|
ProductWarehouses []ProductWarehouse `gorm:"foreignKey:ProductId;references:Id"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,14 @@
|
|||||||
package entities
|
package entities
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProductWarehouse struct {
|
type ProductWarehouse struct {
|
||||||
Id uint `gorm:"primaryKey;autoIncrement"`
|
Id uint `gorm:"primaryKey;column:id"`
|
||||||
ProductId uint `gorm:"not null"`
|
ProductId uint `gorm:"column:product_id;not null"`
|
||||||
WarehouseId uint `gorm:"not null"`
|
WarehouseId uint `gorm:"column:warehouse_id;not null"`
|
||||||
Quantity float64 `gorm:"default:0"`
|
ProjectFlockKandangId *uint `gorm:"column:project_flock_kandang_id"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
Quantity float64 `gorm:"column:qty;type:numeric(15,3);default:0"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
|
||||||
CreatedBy uint `gorm:"not null"`
|
|
||||||
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
Product Product `gorm:"foreignKey:ProductId;references:Id"`
|
Product Product `gorm:"foreignKey:ProductId;references:Id"`
|
||||||
Warehouse Warehouse `gorm:"foreignKey:WarehouseId;references:Id"`
|
Warehouse Warehouse `gorm:"foreignKey:WarehouseId;references:Id"`
|
||||||
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
StockLogs []StockLog `gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
package entities
|
package entities
|
||||||
|
|
||||||
import (
|
import "time"
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LogTypeAdjustment = "ADJUSTMENT"
|
LogTypeAdjustment = "ADJUSTMENT"
|
||||||
@@ -17,19 +13,18 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type StockLog struct {
|
type StockLog struct {
|
||||||
Id uint `gorm:"primaryKey;column:id"`
|
Id uint `gorm:"primaryKey;column:id"`
|
||||||
TransactionType string `gorm:"type:varchar(20);not null"`
|
ProductWarehouseId uint `gorm:"column:product_warehouse_id;not null;index"`
|
||||||
Quantity float64 `gorm:"type:numeric(15,3);not null"`
|
CreatedBy uint `gorm:"column:created_by;not null;index"`
|
||||||
BeforeQuantity float64 `gorm:"type:numeric(15,3);not null"`
|
|
||||||
AfterQuantity float64 `gorm:"type:numeric(15,3);not null"`
|
Increase float64 `gorm:"column:increase;type:numeric(15,3);default:0"`
|
||||||
LogType string `gorm:"type:varchar(50);not null;index:stock_logs_flaggable_lookup,priority:1"`
|
Decrease float64 `gorm:"column:decrease;type:numeric(15,3);default:0"`
|
||||||
LogId uint `gorm:"not null;index:stock_logs_flaggable_lookup,priority:2"`
|
|
||||||
Note string `gorm:"type:text"`
|
LoggableType string `gorm:"column:loggable_type;type:varchar(50);not null"`
|
||||||
ProductWarehouseId uint `gorm:"not null;index"`
|
LoggableId uint `gorm:"column:loggable_id;not null"`
|
||||||
CreatedBy uint `gorm:"index"`
|
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
Notes string `gorm:"column:notes;type:text"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
|
||||||
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
|
|
||||||
|
|
||||||
ProductWarehouse *ProductWarehouse `json:"product_warehouse,omitempty" gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
ProductWarehouse *ProductWarehouse `json:"product_warehouse,omitempty" gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
||||||
CreatedUser *User `json:"created_user,omitempty" gorm:"foreignKey:CreatedBy;references:Id"`
|
CreatedUser *User `json:"created_user,omitempty" gorm:"foreignKey:CreatedBy;references:Id"`
|
||||||
|
|||||||
@@ -104,12 +104,12 @@ func ToProductWarehouseDTO(e *entity.ProductWarehouse) *ProductWarehouseDTO {
|
|||||||
|
|
||||||
func ToAdjustmentRelationDTO(e *entity.StockLog) AdjustmentRelationDTO {
|
func ToAdjustmentRelationDTO(e *entity.StockLog) AdjustmentRelationDTO {
|
||||||
return AdjustmentRelationDTO{
|
return AdjustmentRelationDTO{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
TransactionType: e.TransactionType,
|
// TransactionType: e.LoggableType,
|
||||||
Quantity: e.Quantity,
|
// Quantity: e.Q,
|
||||||
BeforeQuantity: e.BeforeQuantity,
|
// BeforeQuantity: e.BeforeQuantity,
|
||||||
AfterQuantity: e.AfterQuantity,
|
// AfterQuantity: e.AfterQuantity,
|
||||||
Note: e.Note,
|
Note: e.Notes,
|
||||||
ProductWarehouseId: e.ProductWarehouseId,
|
ProductWarehouseId: e.ProductWarehouseId,
|
||||||
ProductWarehouse: ToProductWarehouseDTO(e.ProductWarehouse),
|
ProductWarehouse: ToProductWarehouseDTO(e.ProductWarehouse),
|
||||||
}
|
}
|
||||||
@@ -136,6 +136,6 @@ func ToAdjustmentListDTO(e *entity.StockLog) AdjustmentListDTO {
|
|||||||
func ToAdjustmentDetailDTO(e *entity.StockLog) AdjustmentDetailDTO {
|
func ToAdjustmentDetailDTO(e *entity.StockLog) AdjustmentDetailDTO {
|
||||||
return AdjustmentDetailDTO{
|
return AdjustmentDetailDTO{
|
||||||
AdjustmentListDTO: ToAdjustmentListDTO(e),
|
AdjustmentListDTO: ToAdjustmentListDTO(e),
|
||||||
UpdatedAt: e.UpdatedAt,
|
// UpdatedAt: e.UpdatedAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ func (s *adjustmentService) GetOne(c *fiber.Ctx, id uint) (*entity.StockLog, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if stockLog.LogType != entity.LogTypeAdjustment {
|
if stockLog.LoggableType != entity.LogTypeAdjustment {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Adjustment not found")
|
return nil, fiber.NewError(fiber.StatusNotFound, "Adjustment not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
|
|||||||
ProductId: uint(req.ProductID),
|
ProductId: uint(req.ProductID),
|
||||||
WarehouseId: uint(req.WarehouseID),
|
WarehouseId: uint(req.WarehouseID),
|
||||||
Quantity: 0,
|
Quantity: 0,
|
||||||
CreatedBy: actorID,
|
// CreatedBy: 1, // TODO: should Get from auth middleware
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.ProductWarehouseRepo.CreateOne(ctx, newPW, nil); err != nil {
|
if err := s.ProductWarehouseRepo.CreateOne(ctx, newPW, nil); err != nil {
|
||||||
@@ -128,25 +128,23 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
|
|||||||
}
|
}
|
||||||
|
|
||||||
afterQuantity := productWarehouse.Quantity
|
afterQuantity := productWarehouse.Quantity
|
||||||
|
newLog := &entity.StockLog{
|
||||||
|
// TransactionType: transactionType,
|
||||||
|
LoggableType: entity.LogTypeAdjustment,
|
||||||
|
LoggableId: 0,
|
||||||
|
Notes: req.Note,
|
||||||
|
ProductWarehouseId: productWarehouse.Id,
|
||||||
|
CreatedBy: actorID, // TODO: should Get from auth middleware
|
||||||
|
}
|
||||||
if transactionType == entity.TransactionTypeIncrease {
|
if transactionType == entity.TransactionTypeIncrease {
|
||||||
afterQuantity += req.Quantity
|
afterQuantity += req.Quantity
|
||||||
|
newLog.Increase = afterQuantity
|
||||||
} else {
|
} else {
|
||||||
if productWarehouse.Quantity < req.Quantity {
|
if productWarehouse.Quantity < req.Quantity {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Insufficient stock for adjustment")
|
return fiber.NewError(fiber.StatusBadRequest, "Insufficient stock for adjustment")
|
||||||
}
|
}
|
||||||
afterQuantity -= req.Quantity
|
afterQuantity -= req.Quantity
|
||||||
}
|
newLog.Decrease = afterQuantity
|
||||||
|
|
||||||
newLog := &entity.StockLog{
|
|
||||||
TransactionType: transactionType,
|
|
||||||
Quantity: req.Quantity,
|
|
||||||
BeforeQuantity: productWarehouse.Quantity,
|
|
||||||
AfterQuantity: afterQuantity,
|
|
||||||
LogType: entity.LogTypeAdjustment,
|
|
||||||
LogId: 0,
|
|
||||||
Note: req.Note,
|
|
||||||
ProductWarehouseId: productWarehouse.Id,
|
|
||||||
CreatedBy: actorID,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.StockLogsRepository.WithTx(tx).CreateOne(ctx, newLog, nil); err != nil {
|
if err := s.StockLogsRepository.WithTx(tx).CreateOne(ctx, newLog, nil); err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-stocks/dto"
|
||||||
|
service "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-stocks/services"
|
||||||
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-stocks/validations"
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/response"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
// entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductStockController struct {
|
||||||
|
ProductStockService service.ProductStockService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProductStockController(productStockService service.ProductStockService) *ProductStockController {
|
||||||
|
return &ProductStockController{
|
||||||
|
ProductStockService: productStockService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ProductStockController) GetAll(c *fiber.Ctx) error {
|
||||||
|
query := &validation.Query{
|
||||||
|
Page: c.QueryInt("page", 1),
|
||||||
|
Limit: c.QueryInt("limit", 10),
|
||||||
|
Search: c.Query("search", ""),
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.Page < 1 || query.Limit < 1 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, totalResults, err := u.ProductStockService.GetAll(c, query)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).
|
||||||
|
JSON(response.SuccessWithPaginate[dto.ProductStockListDTO]{
|
||||||
|
Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Get all productStocks successfully",
|
||||||
|
Meta: response.Meta{
|
||||||
|
Page: query.Page,
|
||||||
|
Limit: query.Limit,
|
||||||
|
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
||||||
|
TotalResults: totalResults,
|
||||||
|
},
|
||||||
|
Data: dto.ToProductStockListDTOs(result),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ProductStockController) GetOne(c *fiber.Ctx) error {
|
||||||
|
param := c.Params("id")
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(param)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := u.ProductStockService.GetOne(c, uint(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).
|
||||||
|
JSON(response.Success{
|
||||||
|
Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Retrieved product successfully",
|
||||||
|
Data: dto.ToProductStockDetailDTO(*res),
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto"
|
||||||
|
productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto"
|
||||||
|
uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
|
||||||
|
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// === DTO Structs ===
|
||||||
|
|
||||||
|
type ProductStockRelationDTO struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductStockListDTO struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Brand string `json:"brand"`
|
||||||
|
Sku *string `json:"sku,omitempty"`
|
||||||
|
ProductPrice float64 `json:"product_price"`
|
||||||
|
SellingPrice *float64 `json:"selling_price,omitempty"`
|
||||||
|
Tax *float64 `json:"tax,omitempty"`
|
||||||
|
ExpiryPeriod *int `json:"expiry_period,omitempty"`
|
||||||
|
Flags []string `json:"flags"`
|
||||||
|
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
||||||
|
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
||||||
|
CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
Suppliers []SupplierDTO `json:"suppliers,omitempty"`
|
||||||
|
ProductWarehouses []ProductWarehouseDTO `json:"product_warehouses,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductStockDetailDTO struct {
|
||||||
|
ProductStockListDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
type SupplierDTO struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductWarehouseDTO struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
ProductId uint `json:"product_id"`
|
||||||
|
WarehouseId uint `json:"warehouse_id"`
|
||||||
|
WarehouseName string `json:"warehouse_name"`
|
||||||
|
Location *locationDTO.LocationRelationDTO `json:"location"`
|
||||||
|
CurrentStock float64 `json:"current_stock"`
|
||||||
|
StockLogs []StockLogDetailDTO `json:"stock_logs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StockLogDetailDTO struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
Increase float64 `json:"increase"`
|
||||||
|
Decrease float64 `json:"decrease"`
|
||||||
|
LoggableType string `json:"loggable_type"`
|
||||||
|
LoggableId uint `json:"loggable_id"`
|
||||||
|
Notes *string `json:"notes"`
|
||||||
|
ProductWarehouseId uint `json:"product_warehouse_id"`
|
||||||
|
CreatedBy uint `json:"created_by"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Mapper Functions ===
|
||||||
|
func ToProductStockListDTO(e entity.Product) ProductStockListDTO {
|
||||||
|
var createdUser *userDTO.UserRelationDTO
|
||||||
|
if e.CreatedUser.Id != 0 {
|
||||||
|
mapped := userDTO.ToUserRelationDTO(e.CreatedUser)
|
||||||
|
createdUser = &mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
var categoryRef *productCategoryDTO.ProductCategoryRelationDTO
|
||||||
|
if e.ProductCategory.Id != 0 {
|
||||||
|
mapped := productCategoryDTO.ToProductCategoryRelationDTO(e.ProductCategory)
|
||||||
|
categoryRef = &mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := make([]string, len(e.Flags))
|
||||||
|
for i, f := range e.Flags {
|
||||||
|
flags[i] = f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
var uomRef *uomDTO.UomRelationDTO
|
||||||
|
if e.Uom.Id != 0 {
|
||||||
|
mapped := uomDTO.ToUomRelationDTO(e.Uom)
|
||||||
|
uomRef = &mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProductStockListDTO{
|
||||||
|
Id: e.Id,
|
||||||
|
Name: e.Name,
|
||||||
|
Flags: flags,
|
||||||
|
Uom: uomRef,
|
||||||
|
Brand: e.Brand,
|
||||||
|
Sku: e.Sku,
|
||||||
|
ProductPrice: e.ProductPrice,
|
||||||
|
SellingPrice: e.SellingPrice,
|
||||||
|
Tax: e.Tax,
|
||||||
|
ExpiryPeriod: e.ExpiryPeriod,
|
||||||
|
CreatedAt: e.CreatedAt,
|
||||||
|
UpdatedAt: e.UpdatedAt,
|
||||||
|
CreatedUser: createdUser,
|
||||||
|
ProductCategory: categoryRef,
|
||||||
|
Suppliers: mapSupplierDTOs(e.ProductSuppliers),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToProductStockListDTOs(e []entity.Product) []ProductStockListDTO {
|
||||||
|
result := make([]ProductStockListDTO, len(e))
|
||||||
|
for i, r := range e {
|
||||||
|
result[i] = ToProductStockListDTO(r)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToProductStockDetailDTO(e entity.Product) ProductStockDetailDTO {
|
||||||
|
base := ToProductStockListDTO(e)
|
||||||
|
base.ProductWarehouses = mapProductWarehouseDTOs(e.ProductWarehouses)
|
||||||
|
|
||||||
|
return ProductStockDetailDTO{
|
||||||
|
ProductStockListDTO: base,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- helpers ---
|
||||||
|
|
||||||
|
func mapSupplierDTOs(src []entity.ProductSupplier) []SupplierDTO {
|
||||||
|
if len(src) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result := make([]SupplierDTO, 0, len(src))
|
||||||
|
for _, ps := range src {
|
||||||
|
if ps.Supplier.Id == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, SupplierDTO{
|
||||||
|
Id: ps.Supplier.Id,
|
||||||
|
Name: ps.Supplier.Name,
|
||||||
|
Alias: ps.Supplier.Alias,
|
||||||
|
Category: ps.Supplier.Category,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapProductWarehouseDTOs(src []entity.ProductWarehouse) []ProductWarehouseDTO {
|
||||||
|
if len(src) == 0 {
|
||||||
|
return []ProductWarehouseDTO{}
|
||||||
|
}
|
||||||
|
result := make([]ProductWarehouseDTO, 0, len(src))
|
||||||
|
for _, pw := range src {
|
||||||
|
dto := ProductWarehouseDTO{
|
||||||
|
Id: pw.Id,
|
||||||
|
ProductId: pw.ProductId,
|
||||||
|
WarehouseId: pw.WarehouseId,
|
||||||
|
CurrentStock: pw.Quantity,
|
||||||
|
StockLogs: mapStockLogs(pw.StockLogs),
|
||||||
|
}
|
||||||
|
if pw.Warehouse.Id != 0 {
|
||||||
|
dto.WarehouseName = pw.Warehouse.Name
|
||||||
|
if pw.Warehouse.Location != nil {
|
||||||
|
mapped := locationDTO.ToLocationRelationDTO(*pw.Warehouse.Location)
|
||||||
|
dto.Location = &mapped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = append(result, dto)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapStockLogs(src []entity.StockLog) []StockLogDetailDTO {
|
||||||
|
if len(src) == 0 {
|
||||||
|
return []StockLogDetailDTO{}
|
||||||
|
}
|
||||||
|
result := make([]StockLogDetailDTO, 0, len(src))
|
||||||
|
for _, log := range src {
|
||||||
|
var notes *string
|
||||||
|
if log.Notes != "" {
|
||||||
|
n := log.Notes
|
||||||
|
notes = &n
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, StockLogDetailDTO{
|
||||||
|
Id: log.Id,
|
||||||
|
Increase: log.Increase,
|
||||||
|
Decrease: log.Decrease,
|
||||||
|
LoggableType: log.LoggableType,
|
||||||
|
LoggableId: log.LoggableId,
|
||||||
|
Notes: notes,
|
||||||
|
ProductWarehouseId: log.ProductWarehouseId,
|
||||||
|
CreatedBy: log.CreatedBy,
|
||||||
|
CreatedAt: log.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package productStocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
sProductStock "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-stocks/services"
|
||||||
|
|
||||||
|
rProduct "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/repositories"
|
||||||
|
rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories"
|
||||||
|
sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductStockModule struct{}
|
||||||
|
|
||||||
|
func (ProductStockModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
||||||
|
productRepo := rProduct.NewProductRepository(db)
|
||||||
|
userRepo := rUser.NewUserRepository(db)
|
||||||
|
|
||||||
|
productStockService := sProductStock.NewProductStockService(productRepo, validate)
|
||||||
|
userService := sUser.NewUserService(userRepo, validate)
|
||||||
|
|
||||||
|
ProductStockRoutes(router, userService, productStockService)
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
// import (
|
||||||
|
// entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
// "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||||
|
// "gorm.io/gorm"
|
||||||
|
// )
|
||||||
|
|
||||||
|
// type ProductStockRepository interface {
|
||||||
|
// repository.BaseRepository[entity.ProductStock]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type ProductStockRepositoryImpl struct {
|
||||||
|
// *repository.BaseRepositoryImpl[entity.ProductStock]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func NewProductStockRepository(db *gorm.DB) ProductStockRepository {
|
||||||
|
// return &ProductStockRepositoryImpl{
|
||||||
|
// BaseRepositoryImpl: repository.NewBaseRepository[entity.ProductStock](db),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package productStocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
// m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
|
||||||
|
controller "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-stocks/controllers"
|
||||||
|
productStock "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-stocks/services"
|
||||||
|
user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProductStockRoutes(v1 fiber.Router, u user.UserService, s productStock.ProductStockService) {
|
||||||
|
ctrl := controller.NewProductStockController(s)
|
||||||
|
|
||||||
|
route := v1.Group("/product-stocks")
|
||||||
|
|
||||||
|
// route.Get("/", m.Auth(u), ctrl.GetAll)
|
||||||
|
// route.Post("/", m.Auth(u), ctrl.CreateOne)
|
||||||
|
// route.Get("/:id", m.Auth(u), ctrl.GetOne)
|
||||||
|
// route.Patch("/:id", m.Auth(u), ctrl.UpdateOne)
|
||||||
|
// route.Delete("/:id", m.Auth(u), ctrl.DeleteOne)
|
||||||
|
|
||||||
|
route.Get("/", ctrl.GetAll)
|
||||||
|
route.Get("/:id", ctrl.GetOne)
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-stocks/validations"
|
||||||
|
productRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/repositories"
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductStockService interface {
|
||||||
|
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.Product, int64, error)
|
||||||
|
GetOne(ctx *fiber.Ctx, id uint) (*entity.Product, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type productStockService struct {
|
||||||
|
Log *logrus.Logger
|
||||||
|
Validate *validator.Validate
|
||||||
|
ProductRepository productRepository.ProductRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProductStockService(
|
||||||
|
productRepo productRepository.ProductRepository,
|
||||||
|
validate *validator.Validate,
|
||||||
|
) ProductStockService {
|
||||||
|
return &productStockService{
|
||||||
|
Log: utils.Log,
|
||||||
|
Validate: validate,
|
||||||
|
ProductRepository: productRepo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s productStockService) withRelations(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.
|
||||||
|
Preload("CreatedUser").
|
||||||
|
Preload("Uom").
|
||||||
|
Preload("ProductCategory").
|
||||||
|
Preload("Flags").
|
||||||
|
Preload("ProductWarehouses").
|
||||||
|
Preload("ProductWarehouses.Warehouse").
|
||||||
|
Preload("ProductWarehouses.Warehouse.Location").
|
||||||
|
Preload("ProductWarehouses.Warehouse.Location.Area").
|
||||||
|
Preload("ProductWarehouses.StockLogs", func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Order("created_at ASC")
|
||||||
|
}).
|
||||||
|
Preload("ProductSuppliers").
|
||||||
|
Preload("ProductSuppliers.Supplier", func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Order("suppliers.name ASC")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s productStockService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.Product, int64, error) {
|
||||||
|
if err := s.Validate.Struct(params); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := (params.Page - 1) * params.Limit
|
||||||
|
|
||||||
|
productStocks, total, err := s.ProductRepository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
||||||
|
db = s.withRelations(db)
|
||||||
|
if params.Search != "" {
|
||||||
|
return db.Where("name ILIKE ?", "%"+params.Search+"%")
|
||||||
|
}
|
||||||
|
return db.Order("created_at DESC").Order("updated_at DESC")
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to get productStocks: %+v", err)
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return productStocks, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s productStockService) GetOne(c *fiber.Ctx, id uint) (*entity.Product, error) {
|
||||||
|
product, err := s.ProductRepository.GetByID(c.Context(), id, s.withRelations)
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "Product not found")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed get product by id: %+v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return product, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package validation
|
||||||
|
|
||||||
|
type Create struct {
|
||||||
|
Name string `json:"name" validate:"required_strict,min=3"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Update struct {
|
||||||
|
Name *string `json:"name,omitempty" validate:"omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query struct {
|
||||||
|
Page int `query:"page" validate:"omitempty,number,min=1,gt=0"`
|
||||||
|
Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"`
|
||||||
|
Search string `query:"search" validate:"omitempty,max=50"`
|
||||||
|
}
|
||||||
@@ -98,8 +98,8 @@ func ToProductWarehouseNestedDTO(e entity.ProductWarehouse) ProductWarehousNeste
|
|||||||
func ToProductWarehouseListDTO(e entity.ProductWarehouse) ProductWarehouseListDTO {
|
func ToProductWarehouseListDTO(e entity.ProductWarehouse) ProductWarehouseListDTO {
|
||||||
dto := ProductWarehouseListDTO{
|
dto := ProductWarehouseListDTO{
|
||||||
ProductWarehouseRelationDTO: ToProductWarehouseRelationDTO(e),
|
ProductWarehouseRelationDTO: ToProductWarehouseRelationDTO(e),
|
||||||
CreatedAt: e.CreatedAt,
|
// CreatedAt: e.CreatedAt,
|
||||||
UpdatedAt: e.UpdatedAt,
|
// UpdatedAt: e.UpdatedAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map Product relation jika ada
|
// Map Product relation jika ada
|
||||||
@@ -140,13 +140,13 @@ func ToProductWarehouseListDTO(e entity.ProductWarehouse) ProductWarehouseListDT
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Map CreatedUser relation jika ada
|
// Map CreatedUser relation jika ada
|
||||||
if e.CreatedUser.Id != 0 {
|
// if e.CreatedUser.Id != 0 {
|
||||||
user := UserRelationDTO{
|
// user := UserRelationDTO{
|
||||||
Id: e.CreatedUser.Id,
|
// Id: e.CreatedUser.Id,
|
||||||
Username: e.CreatedUser.Name,
|
// Username: e.CreatedUser.Name,
|
||||||
}
|
// }
|
||||||
dto.CreatedUser = &user
|
// dto.CreatedUser = &user
|
||||||
}
|
// }
|
||||||
|
|
||||||
return dto
|
return dto
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -213,11 +213,11 @@ func (r *ProductWarehouseRepositoryImpl) EnsureProductWarehouse(
|
|||||||
ProductId: productID,
|
ProductId: productID,
|
||||||
WarehouseId: warehouseID,
|
WarehouseId: warehouseID,
|
||||||
Quantity: 0,
|
Quantity: 0,
|
||||||
CreatedBy: uint(createdBy),
|
// CreatedBy: uint(createdBy),
|
||||||
}
|
|
||||||
if entity.CreatedBy == 0 {
|
|
||||||
entity.CreatedBy = 1
|
|
||||||
}
|
}
|
||||||
|
// if entity.CreatedBy == 0 {
|
||||||
|
// entity.CreatedBy = 1
|
||||||
|
// }
|
||||||
|
|
||||||
if err := r.CreateOne(ctx, entity, nil); err != nil {
|
if err := r.CreateOne(ctx, entity, nil); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
adjustments "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/adjustments"
|
adjustments "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/adjustments"
|
||||||
|
productStocks "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-stocks"
|
||||||
productWarehouses "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses"
|
productWarehouses "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses"
|
||||||
transfers "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/transfers"
|
transfers "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/transfers"
|
||||||
// MODULE IMPORTS
|
// MODULE IMPORTS
|
||||||
@@ -21,6 +22,7 @@ func RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Valida
|
|||||||
|
|
||||||
adjustments.AdjustmentModule{},
|
adjustments.AdjustmentModule{},
|
||||||
transfers.TransferModule{},
|
transfers.TransferModule{},
|
||||||
|
productStocks.ProductStockModule{},
|
||||||
// MODULE REGISTRY
|
// MODULE REGISTRY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -271,15 +271,18 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
|||||||
s.Log.Infof("Source product warehouse updated: %+v", sourcePW.Id)
|
s.Log.Infof("Source product warehouse updated: %+v", sourcePW.Id)
|
||||||
|
|
||||||
// create stock log for decrease (source)
|
// create stock log for decrease (source)
|
||||||
beforeQty := sourcePW.Quantity + product.ProductQty // sourcePW already decreased
|
// beforeQty := sourcePW.Quantity + product.ProductQty // sourcePW already decreased
|
||||||
decreaseLog := &entity.StockLog{
|
decreaseLog := &entity.StockLog{
|
||||||
TransactionType: entity.TransactionTypeDecrease,
|
// TransactionType: entity.TransactionTypeDecrease,
|
||||||
Quantity: product.ProductQty,
|
// Quantity: product.ProductQty,
|
||||||
BeforeQuantity: beforeQty,
|
// BeforeQuantity: beforeQty,
|
||||||
AfterQuantity: sourcePW.Quantity,
|
// AfterQuantity: sourcePW.Qty,
|
||||||
LogType: entity.LogTypeTransfer,
|
// LogType: entity.LogTypeTransfer,
|
||||||
LogId: uint(entityTransfer.Id),
|
// LogId: uint(entityTransfer.Id),
|
||||||
Note: "",
|
Decrease: product.ProductQty,
|
||||||
|
Notes: "",
|
||||||
|
LoggableType: entity.LogTypeTransfer,
|
||||||
|
LoggableId: uint(entityTransfer.Id),
|
||||||
ProductWarehouseId: sourcePW.Id,
|
ProductWarehouseId: sourcePW.Id,
|
||||||
CreatedBy: actorID,
|
CreatedBy: actorID,
|
||||||
}
|
}
|
||||||
@@ -302,7 +305,7 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
|||||||
ProductId: uint(product.ProductID),
|
ProductId: uint(product.ProductID),
|
||||||
WarehouseId: uint(req.DestinationWarehouseID),
|
WarehouseId: uint(req.DestinationWarehouseID),
|
||||||
Quantity: 0,
|
Quantity: 0,
|
||||||
CreatedBy: actorID,
|
// CreatedBy: 1, // TODO: should Get from auth middleware
|
||||||
}
|
}
|
||||||
if err := s.ProductWarehouseRepo.WithTx(tx).CreateOne(c.Context(), destPW, nil); err != nil {
|
if err := s.ProductWarehouseRepo.WithTx(tx).CreateOne(c.Context(), destPW, nil); err != nil {
|
||||||
s.Log.Errorf("Failed to create destination product warehouse: %+v", err)
|
s.Log.Errorf("Failed to create destination product warehouse: %+v", err)
|
||||||
@@ -319,15 +322,16 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
|||||||
s.Log.Infof("Destination product warehouse updated: %+v", destPW.Id)
|
s.Log.Infof("Destination product warehouse updated: %+v", destPW.Id)
|
||||||
|
|
||||||
// create stock log for increase (destination)
|
// create stock log for increase (destination)
|
||||||
beforeDestQty := destPW.Quantity - product.ProductQty
|
// beforeDestQty := destPW.Quantity - product.ProductQty
|
||||||
increaseLog := &entity.StockLog{
|
increaseLog := &entity.StockLog{
|
||||||
TransactionType: entity.TransactionTypeIncrease,
|
// TransactionType: entity.TransactionTypeIncrease,
|
||||||
Quantity: product.ProductQty,
|
// Quantity: product.ProductQty,
|
||||||
BeforeQuantity: beforeDestQty,
|
// BeforeQuantity: beforeDestQty,
|
||||||
AfterQuantity: destPW.Quantity,
|
// AfterQuantity: destPW.Qty,
|
||||||
LogType: entity.LogTypeTransfer,
|
Increase: product.ProductQty,
|
||||||
LogId: uint(entityTransfer.Id),
|
LoggableType: entity.LogTypeTransfer,
|
||||||
Note: "",
|
LoggableId: uint(entityTransfer.Id),
|
||||||
|
Notes: "",
|
||||||
ProductWarehouseId: destPW.Id,
|
ProductWarehouseId: destPW.Id,
|
||||||
CreatedBy: actorID,
|
CreatedBy: actorID,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ func (s *chickinService) getOrCreateProductWarehouse(ctx *fiber.Ctx, warehouseId
|
|||||||
ProductId: product.Id,
|
ProductId: product.Id,
|
||||||
WarehouseId: warehouseId,
|
WarehouseId: warehouseId,
|
||||||
Quantity: 0,
|
Quantity: 0,
|
||||||
CreatedBy: actorID,
|
// CreatedBy: actorID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.ProductWarehouseRepo.WithTx(dbTransaction).CreateOne(ctx.Context(), newPW, nil); err != nil {
|
if err := s.ProductWarehouseRepo.WithTx(dbTransaction).CreateOne(ctx.Context(), newPW, nil); err != nil {
|
||||||
|
|||||||
@@ -778,7 +778,7 @@ func (s *transferLayingService) getOrCreateProductWarehouse(ctx context.Context,
|
|||||||
ProductId: productID,
|
ProductId: productID,
|
||||||
WarehouseId: warehouseID,
|
WarehouseId: warehouseID,
|
||||||
Quantity: quantity,
|
Quantity: quantity,
|
||||||
CreatedBy: actorID,
|
// CreatedBy: actorID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := productWarehouseRepoTx.CreateOne(ctx, newWarehouse, nil); err != nil {
|
if err := productWarehouseRepoTx.CreateOne(ctx, newWarehouse, nil); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user