mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Merge branch 'development' of https://gitlab.com/mbugroup/lti-api into dev/teguh
This commit is contained in:
@@ -101,6 +101,26 @@ func ToSalesDTO(e entity.MarketingDeliveryProduct) SalesDTO {
|
||||
}
|
||||
}
|
||||
|
||||
func ToSalesAgeDTO(e entity.MarketingDeliveryProduct) SalesDTO {
|
||||
|
||||
productFlags := make([]string, len(e.MarketingProduct.ProductWarehouse.Product.Flags))
|
||||
for i, f := range e.MarketingProduct.ProductWarehouse.Product.Flags {
|
||||
productFlags[i] = f.Name
|
||||
}
|
||||
|
||||
var category string
|
||||
if e.MarketingProduct.ProductWarehouse.ProjectFlockKandang != nil {
|
||||
category = e.MarketingProduct.ProductWarehouse.ProjectFlockKandang.ProjectFlock.Category
|
||||
}
|
||||
|
||||
ageInDay, _ := calculateAgeFromChickin(e.MarketingProduct.ProductWarehouse.ProjectFlockKandang, e.DeliveryDate, productFlags, category)
|
||||
|
||||
return SalesDTO{
|
||||
Age: ageInDay,
|
||||
Qty: e.UsageQty,
|
||||
}
|
||||
}
|
||||
|
||||
func ToSummaryDto(e []entity.MarketingDeliveryProduct) SummaryDTO {
|
||||
|
||||
var totalSalesPrice, totalActualPrice, sumSales, sumActual float64
|
||||
|
||||
@@ -367,7 +367,7 @@ func (s closingService) GetClosingSapronak(c *fiber.Ctx, projectFlockID uint, pa
|
||||
return nil, 0, fiber.NewError(fiber.StatusBadRequest, "type must be either incoming or outgoing")
|
||||
}
|
||||
|
||||
warehouseIDs, err := s.getWarehouseIDsByProjectFlock(c.Context(), projectFlockID)
|
||||
warehouseIDs, err := s.getWarehouseIDsByProjectFlock(c.Context(), projectFlockID, params.KandangID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to fetch warehouses for project flock %d: %+v", projectFlockID, err)
|
||||
return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch warehouses for project flock")
|
||||
@@ -451,7 +451,7 @@ func (s closingService) GetClosingSapronakSummary(c *fiber.Ctx, projectFlockID u
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock")
|
||||
}
|
||||
|
||||
warehouseIDs, err := s.getWarehouseIDsByProjectFlock(c.Context(), projectFlockID)
|
||||
warehouseIDs, err := s.getWarehouseIDsByProjectFlock(c.Context(), projectFlockID, params.KandangID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to fetch warehouses for project flock %d: %+v", projectFlockID, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch warehouses for project flock")
|
||||
@@ -494,13 +494,16 @@ func (s closingService) GetClosingSapronakSummary(c *fiber.Ctx, projectFlockID u
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (s closingService) getWarehouseIDsByProjectFlock(ctx context.Context, projectFlockID uint) ([]uint, error) {
|
||||
func (s closingService) getWarehouseIDsByProjectFlock(ctx context.Context, projectFlockID uint, kandangID *uint) ([]uint, error) {
|
||||
var kandangIDs []uint
|
||||
db := s.Repository.DB().WithContext(ctx)
|
||||
|
||||
if err := db.Model(&entity.ProjectFlockKandang{}).
|
||||
Where("project_flock_id = ?", projectFlockID).
|
||||
Pluck("kandang_id", &kandangIDs).Error; err != nil {
|
||||
query := db.Model(&entity.ProjectFlockKandang{}).
|
||||
Where("project_flock_id = ?", projectFlockID)
|
||||
if kandangID != nil && *kandangID > 0 {
|
||||
query = query.Where("id = ?", *kandangID)
|
||||
}
|
||||
if err := query.Pluck("kandang_id", &kandangIDs).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -841,7 +844,7 @@ func (s closingService) GetClosingDataProduksi(c *fiber.Ctx, projectFlockID uint
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch FCR standard data")
|
||||
}
|
||||
}
|
||||
age, err := s.calculateAverageSalesAge(c.Context(), projectFlockID)
|
||||
age, err := s.calculateAverageSalesAge(c.Context(), projectFlockID, kandangID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to calculate sales age for project flock %d: %+v", projectFlockID, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch sales age data")
|
||||
@@ -1028,38 +1031,24 @@ func (s closingService) GetClosingDataProduksi(c *fiber.Ctx, projectFlockID uint
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s closingService) calculateAverageSalesAge(ctx context.Context, projectFlockID uint) (float64, error) {
|
||||
deliveryProducts, err := s.MarketingDeliveryProductRepo.GetDeliveryProductsByProjectFlockID(ctx, projectFlockID, func(db *gorm.DB) *gorm.DB {
|
||||
return db.
|
||||
Preload("MarketingProduct").
|
||||
Preload("MarketingProduct.ProductWarehouse").
|
||||
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang").
|
||||
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Chickins")
|
||||
})
|
||||
func (s closingService) calculateAverageSalesAge(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) (float64, error) {
|
||||
penjualan, err := s.MarketingDeliveryProductRepo.GetClosingPenjualanForAgeChickDataProduction(ctx, projectFlockID, projectFlockKandangID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var (
|
||||
totalQty float64
|
||||
totalAgeWeeks float64
|
||||
)
|
||||
|
||||
for _, product := range deliveryProducts {
|
||||
if product.UsageQty == 0 {
|
||||
continue
|
||||
}
|
||||
projectFlockKandang := product.MarketingProduct.ProductWarehouse.ProjectFlockKandang
|
||||
ageWeeks := dto.CalculateAgeFromChickinDataProduksi(projectFlockKandang, product.DeliveryDate)
|
||||
totalAgeWeeks += float64(ageWeeks) * product.UsageQty
|
||||
totalQty += product.UsageQty
|
||||
acumulateAgeQty := 0.0
|
||||
totalQty := 0.0
|
||||
for _, v := range penjualan {
|
||||
sale := dto.ToSalesAgeDTO(v)
|
||||
acumulateAgeQty += float64(sale.Age) * sale.Qty
|
||||
totalQty += sale.Qty
|
||||
}
|
||||
if totalQty > 0 {
|
||||
averageAge := acumulateAgeQty / totalQty
|
||||
return averageAge, nil
|
||||
}
|
||||
|
||||
if totalQty == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return totalAgeWeeks / totalQty, nil
|
||||
return 0, err
|
||||
}
|
||||
|
||||
func (s closingService) determineProductionWeek(ctx context.Context, projectFlockKandangIDs []uint) (int, error) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"math"
|
||||
"mime/multipart"
|
||||
"strconv"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/dto"
|
||||
@@ -362,6 +363,9 @@ func (u *DailyChecklistController) UpdateOne(c *fiber.Ctx) error {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form")
|
||||
}
|
||||
req.Documents = form.File["documents"]
|
||||
if err := validateDailyChecklistDocumentSizes(req.Documents); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
@@ -381,6 +385,16 @@ func (u *DailyChecklistController) UpdateOne(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
func validateDailyChecklistDocumentSizes(files []*multipart.FileHeader) error {
|
||||
const maxDailyChecklistDocumentBytes = 5 * 1024 * 1024 // 5MB
|
||||
for _, file := range files {
|
||||
if file != nil && file.Size > maxDailyChecklistDocumentBytes {
|
||||
return fiber.NewError(fiber.StatusRequestEntityTooLarge, "Document size must be <= 5MB")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DailyChecklistController) DeleteOne(c *fiber.Ctx) error {
|
||||
param := c.Params("idDailyChecklist")
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -259,8 +260,9 @@ func (s dailyChecklistService) GetAll(c *fiber.Ctx, params *validation.Query) ([
|
||||
}
|
||||
|
||||
if params.Search != "" {
|
||||
like := "%" + params.Search + "%"
|
||||
db = db.Where("(k.name ILIKE ? OR dc.category::text ILIKE ?)", like, like)
|
||||
re := regexp.MustCompile("[^a-zA-Z0-9]")
|
||||
like := re.ReplaceAll([]byte("%"+params.Search+"%"), []byte(""))
|
||||
db = db.Where("(regexp_replace(k.name, '[^a-zA-Z0-9]', '', 'g') ILIKE ? OR regexp_replace(dc.category::text, '[^a-zA-Z0-9]', '', 'g') ILIKE ?)", string(like), string(like))
|
||||
}
|
||||
|
||||
countDB := db.Session(&gorm.Session{})
|
||||
|
||||
@@ -169,15 +169,30 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
|
||||
CreatedBy: actorID,
|
||||
}
|
||||
|
||||
stockLogs, err := s.StockLogsRepository.GetByProductWarehouse(ctx, productWarehouse.Id, 1)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get stock logs: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
newLog.Stock = latestStockLog.Stock
|
||||
} else {
|
||||
newLog.Stock = 0
|
||||
}
|
||||
|
||||
if transactionType == string(utils.StockLogTransactionTypeIncrease) {
|
||||
afterQuantity += req.Quantity
|
||||
newLog.Increase = req.Quantity
|
||||
newLog.Stock += newLog.Increase
|
||||
} else {
|
||||
if productWarehouse.Quantity < req.Quantity {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Stok tidak mencukupi untuk pengurangan. Stok saat ini: %.2f, Jumlah yang akan dikurangi: %.2f", productWarehouse.Quantity, req.Quantity))
|
||||
}
|
||||
afterQuantity -= req.Quantity
|
||||
newLog.Decrease = req.Quantity
|
||||
newLog.Stock -= newLog.Decrease
|
||||
}
|
||||
|
||||
if err := s.StockLogsRepository.WithTx(tx).CreateOne(ctx, newLog, nil); err != nil {
|
||||
|
||||
@@ -476,6 +476,18 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
LoggableId: uint(detail.Id),
|
||||
Notes: "",
|
||||
}
|
||||
stockLogs, err := s.StockLogsRepository.GetByProductWarehouse(c.Context(), uint(*detail.SourceProductWarehouseID), 1)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get stock logs: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
stockLogDecrease.Stock -= latestStockLog.Stock - stockLogDecrease.Decrease
|
||||
} else {
|
||||
stockLogDecrease.Stock -= stockLogDecrease.Decrease
|
||||
}
|
||||
|
||||
if err := stocklogsRepoTx.CreateOne(c.Context(), stockLogDecrease, nil); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok keluar")
|
||||
}
|
||||
@@ -512,6 +524,17 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
LoggableId: uint(detail.Id),
|
||||
Notes: "",
|
||||
}
|
||||
stockLogs, err = s.StockLogsRepository.GetByProductWarehouse(c.Context(), uint(*detail.DestProductWarehouseID), 1)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get stock logs: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
stockLogIncrease.Stock = latestStockLog.Stock + stockLogIncrease.Increase
|
||||
} else {
|
||||
stockLogIncrease.Stock += stockLogIncrease.Increase
|
||||
}
|
||||
if err := stocklogsRepoTx.CreateOne(c.Context(), stockLogIncrease, nil); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok masuk")
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type MarketingDeliveryProductRepository interface {
|
||||
UpdateFifoFields(ctx context.Context, id uint, usageQty, pendingQty float64) error
|
||||
GetUsageQty(ctx context.Context, id uint) (float64, error)
|
||||
ResetFifoFields(ctx context.Context, id uint) error
|
||||
GetClosingPenjualanForAgeChickDataProduction(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error)
|
||||
}
|
||||
|
||||
type MarketingDeliveryProductRepositoryImpl struct {
|
||||
@@ -93,6 +94,46 @@ func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualan(ctx context
|
||||
return deliveryProducts, nil
|
||||
}
|
||||
|
||||
func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualanForAgeChickDataProduction(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error) {
|
||||
var deliveryProducts []entity.MarketingDeliveryProduct
|
||||
|
||||
db := r.DB().WithContext(ctx).
|
||||
Joins("JOIN marketing_products ON marketing_products.id = marketing_delivery_products.marketing_product_id").
|
||||
Joins("JOIN product_warehouses ON product_warehouses.id = marketing_products.product_warehouse_id").
|
||||
Joins("JOIN products ON products.id = product_warehouses.product_id").
|
||||
Joins("JOIN flags ON flags.flagable_id = products.id AND flags.flagable_type = 'products'").
|
||||
Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = product_warehouses.project_flock_kandang_id").
|
||||
Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
|
||||
Where("flags.name IN (?)", []string{
|
||||
string(utils.FlagAyamAfkir),
|
||||
string(utils.FlagAyamCulling),
|
||||
string(utils.FlagPullet),
|
||||
string(utils.FlagLayer),
|
||||
}).
|
||||
Where("marketing_delivery_products.delivery_date IS NOT NULL").
|
||||
Distinct("marketing_delivery_products.*")
|
||||
|
||||
if projectFlockKandangID != nil {
|
||||
db = db.Where("product_warehouses.project_flock_kandang_id = ?", *projectFlockKandangID)
|
||||
}
|
||||
|
||||
db = db.
|
||||
Preload("MarketingProduct").
|
||||
Preload("MarketingProduct.ProductWarehouse").
|
||||
Preload("MarketingProduct.ProductWarehouse.Product").
|
||||
Preload("MarketingProduct.ProductWarehouse.Product.ProductCategory").
|
||||
Preload("MarketingProduct.ProductWarehouse.Product.Flags").
|
||||
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang").
|
||||
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Chickins").
|
||||
Order("marketing_delivery_products.delivery_date DESC")
|
||||
|
||||
if err := db.Find(&deliveryProducts).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return deliveryProducts, nil
|
||||
}
|
||||
|
||||
func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualanByCategory(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint, category string) ([]entity.MarketingDeliveryProduct, error) {
|
||||
var deliveryProducts []entity.MarketingDeliveryProduct
|
||||
|
||||
|
||||
@@ -410,6 +410,7 @@ func (s deliveryOrdersService) UpdateOne(c *fiber.Ctx, req *validation.DeliveryO
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch delivery product")
|
||||
}
|
||||
|
||||
oldRequestedQty := deliveryProduct.UsageQty + deliveryProduct.PendingQty
|
||||
var itemDeliveryDate *time.Time
|
||||
if requestedProduct.DeliveryDate != "" {
|
||||
parsedDate, err := utils.ParseDateString(requestedProduct.DeliveryDate)
|
||||
@@ -421,11 +422,8 @@ func (s deliveryOrdersService) UpdateOne(c *fiber.Ctx, req *validation.DeliveryO
|
||||
itemDeliveryDate = deliveryProduct.DeliveryDate
|
||||
}
|
||||
|
||||
oldRequestedQty := deliveryProduct.UsageQty + deliveryProduct.PendingQty
|
||||
|
||||
// Cek apakah product punya flag PAKAN atau OVK
|
||||
isPakanOrOVK := false
|
||||
if foundMarketingProduct.ProductWarehouse.Product.Id != 0 && len(foundMarketingProduct.ProductWarehouse.Product.Flags) > 0 {
|
||||
if foundMarketingProduct.ProductWarehouse.Id != 0 && foundMarketingProduct.ProductWarehouse.Product.Id != 0 && len(foundMarketingProduct.ProductWarehouse.Product.Flags) > 0 {
|
||||
for _, flag := range foundMarketingProduct.ProductWarehouse.Product.Flags {
|
||||
if flag.Name == string(utils.FlagPakan) || flag.Name == string(utils.FlagOVK) {
|
||||
isPakanOrOVK = true
|
||||
@@ -506,60 +504,82 @@ func (s deliveryOrdersService) consumeDeliveryStock(ctx context.Context, tx *gor
|
||||
|
||||
deliveryProductRepo := marketingRepo.NewMarketingDeliveryProductRepository(tx)
|
||||
|
||||
if err == nil && result.UsageQuantity > 0 {
|
||||
if actorID > 0 {
|
||||
decreaseLog := &entity.StockLog{
|
||||
Decrease: result.UsageQuantity,
|
||||
LoggableType: string(utils.StockLogTypeMarketing),
|
||||
LoggableId: deliveryProduct.Id,
|
||||
ProductWarehouseId: marketingProduct.ProductWarehouseId,
|
||||
CreatedBy: actorID,
|
||||
Notes: "",
|
||||
}
|
||||
s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil)
|
||||
}
|
||||
totalConsumed := 0.0
|
||||
var fifoConsumed float64
|
||||
var directConsumed float64
|
||||
|
||||
if result != nil && result.UsageQuantity > 0 {
|
||||
fifoConsumed = result.UsageQuantity
|
||||
totalConsumed = result.UsageQuantity
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err != nil || (totalConsumed < requestedQty) {
|
||||
remainder := requestedQty - totalConsumed
|
||||
|
||||
pwRepo := productWarehouseRepo.NewProductWarehouseRepository(tx)
|
||||
pw, err2 := pwRepo.GetByID(ctx, marketingProduct.ProductWarehouseId, nil)
|
||||
if err2 != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to check product warehouse stock")
|
||||
}
|
||||
|
||||
if pw == nil || pw.Quantity < requestedQty {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Insufficient stock. Available: %.2f, Requested: %.2f", func() float64 {
|
||||
if pw == nil || pw.Quantity < remainder {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Insufficient stock. FIFO: %.2f, Direct Available: %.2f, Total Needed: %.2f", func() float64 {
|
||||
if pw != nil {
|
||||
return pw.Quantity
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}(), requestedQty))
|
||||
}(), remainder, requestedQty))
|
||||
}
|
||||
|
||||
if err := deliveryProductRepo.UpdateFifoFields(ctx, deliveryProduct.Id, requestedQty, 0); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update delivery product")
|
||||
if err := pwRepo.AdjustQuantities(ctx, map[uint]float64{
|
||||
marketingProduct.ProductWarehouseId: -remainder,
|
||||
}, func(db *gorm.DB) *gorm.DB {
|
||||
return tx
|
||||
}); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to adjust product warehouse quantity")
|
||||
}
|
||||
|
||||
if actorID > 0 {
|
||||
decreaseLog := &entity.StockLog{
|
||||
Decrease: requestedQty,
|
||||
LoggableType: string(utils.StockLogTypeMarketing),
|
||||
LoggableId: deliveryProduct.Id,
|
||||
ProductWarehouseId: marketingProduct.ProductWarehouseId,
|
||||
CreatedBy: actorID,
|
||||
Notes: "",
|
||||
}
|
||||
s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
directConsumed = remainder
|
||||
totalConsumed += remainder
|
||||
}
|
||||
|
||||
if err := deliveryProductRepo.UpdateFifoFields(ctx, deliveryProduct.Id, result.UsageQuantity, result.PendingQuantity); err != nil {
|
||||
if err := deliveryProductRepo.UpdateFifoFields(ctx, deliveryProduct.Id, totalConsumed, 0); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update delivery product")
|
||||
}
|
||||
|
||||
if actorID > 0 && totalConsumed > 0 {
|
||||
notes := ""
|
||||
if fifoConsumed > 0 && directConsumed > 0 {
|
||||
notes = fmt.Sprintf("Partial FIFO (%.2f) + Direct (%.2f)", fifoConsumed, directConsumed)
|
||||
} else if fifoConsumed > 0 {
|
||||
notes = fmt.Sprintf("FIFO stock only (%.2f)", fifoConsumed)
|
||||
} else if directConsumed > 0 {
|
||||
notes = fmt.Sprintf("Direct stock only (%.2f)", directConsumed)
|
||||
}
|
||||
|
||||
decreaseLog := &entity.StockLog{
|
||||
Decrease: totalConsumed,
|
||||
LoggableType: string(utils.StockLogTypeMarketing),
|
||||
LoggableId: deliveryProduct.Id,
|
||||
ProductWarehouseId: marketingProduct.ProductWarehouseId,
|
||||
CreatedBy: actorID,
|
||||
Notes: notes,
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, marketingProduct.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
decreaseLog.Stock = latestStockLog.Stock
|
||||
decreaseLog.Stock -= decreaseLog.Decrease
|
||||
} else {
|
||||
decreaseLog.Stock -= decreaseLog.Decrease
|
||||
}
|
||||
s.StockLogRepo.WithTx(tx).CreateOne(ctx, decreaseLog, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -599,6 +619,18 @@ func (s deliveryOrdersService) releaseDeliveryStock(ctx context.Context, tx *gor
|
||||
CreatedBy: actorID,
|
||||
Notes: "",
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, marketingProduct.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
increaseLog.Stock = latestStockLog.Stock
|
||||
increaseLog.Stock += increaseLog.Increase
|
||||
} else {
|
||||
increaseLog.Stock += increaseLog.Increase
|
||||
}
|
||||
|
||||
s.StockLogRepo.WithTx(tx).CreateOne(ctx, increaseLog, nil)
|
||||
}
|
||||
|
||||
|
||||
@@ -645,6 +645,18 @@ func (s *chickinService) ConsumeChickinStocks(ctx context.Context, tx *gorm.DB,
|
||||
CreatedBy: actorID,
|
||||
Notes: fmt.Sprintf("Chickin #%d", chickin.Id),
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, chickin.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
decreaseLog.Stock = latestStockLog.Stock
|
||||
decreaseLog.Stock -= decreaseLog.Decrease
|
||||
} else {
|
||||
decreaseLog.Stock -= decreaseLog.Decrease
|
||||
}
|
||||
|
||||
s.StockLogRepo.CreateOne(ctx, decreaseLog, nil)
|
||||
}
|
||||
|
||||
@@ -701,6 +713,18 @@ func (s *chickinService) ReleaseChickinStocks(ctx context.Context, tx *gorm.DB,
|
||||
CreatedBy: actorID,
|
||||
Notes: fmt.Sprintf("Chickin #%d - Stock released", chickin.Id),
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, chickin.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
increaseLog.Stock = latestStockLog.Stock
|
||||
increaseLog.Stock += increaseLog.Increase
|
||||
} else {
|
||||
increaseLog.Stock += increaseLog.Increase
|
||||
}
|
||||
|
||||
s.StockLogRepo.CreateOne(ctx, increaseLog, nil)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
@@ -19,9 +23,6 @@ import (
|
||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils/fifo"
|
||||
recordingutil "gitlab.com/mbugroup/lti-api.git/internal/utils/recording"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
@@ -535,6 +536,17 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
||||
if egg.ProductWarehouseId == 0 || egg.Qty <= 0 {
|
||||
continue
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, egg.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get stock logs: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
latestStockLog := &entity.StockLog{}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog = stockLogs[0]
|
||||
} else {
|
||||
latestStockLog.Stock = 0
|
||||
}
|
||||
logs = append(logs, &entity.StockLog{
|
||||
ProductWarehouseId: egg.ProductWarehouseId,
|
||||
CreatedBy: actorID,
|
||||
@@ -542,6 +554,7 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
||||
LoggableType: string(utils.StockLogTypeRecording),
|
||||
LoggableId: recordingEntity.Id,
|
||||
Notes: note,
|
||||
Stock: latestStockLog.Stock - float64(egg.Qty),
|
||||
})
|
||||
}
|
||||
if len(logs) > 0 {
|
||||
@@ -937,6 +950,18 @@ func (s *recordingService) consumeRecordingStocks(
|
||||
LoggableId: stock.RecordingId,
|
||||
Notes: note,
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, stock.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
log.Stock = latestStockLog.Stock
|
||||
log.Stock -= log.Decrease
|
||||
} else {
|
||||
log.Stock -= log.Decrease
|
||||
}
|
||||
|
||||
if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1004,6 +1029,18 @@ func (s *recordingService) consumeRecordingDepletions(
|
||||
LoggableId: depletion.RecordingId,
|
||||
Notes: note,
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, sourceWarehouseID, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
log.Stock = latestStockLog.Stock
|
||||
log.Stock -= log.Decrease
|
||||
} else {
|
||||
log.Stock -= log.Decrease
|
||||
}
|
||||
|
||||
if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1022,6 +1059,18 @@ func (s *recordingService) consumeRecordingDepletions(
|
||||
LoggableId: depletion.RecordingId,
|
||||
Notes: note,
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, depletion.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
log.Stock = latestStockLog.Stock
|
||||
log.Stock += log.Increase
|
||||
} else {
|
||||
log.Stock += log.Increase
|
||||
}
|
||||
|
||||
if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1082,6 +1131,18 @@ func (s *recordingService) releaseRecordingStocks(
|
||||
LoggableId: stock.RecordingId,
|
||||
Notes: note,
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, stock.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
log.Stock = latestStockLog.Stock
|
||||
log.Stock += log.Increase
|
||||
} else {
|
||||
log.Stock += log.Increase
|
||||
}
|
||||
|
||||
if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1144,6 +1205,18 @@ func (s *recordingService) releaseRecordingDepletions(
|
||||
LoggableId: depletion.RecordingId,
|
||||
Notes: note,
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, sourceWarehouseID, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
log.Stock = latestStockLog.Stock
|
||||
log.Stock += log.Increase
|
||||
} else {
|
||||
log.Stock += log.Increase
|
||||
}
|
||||
|
||||
if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1162,6 +1235,18 @@ func (s *recordingService) releaseRecordingDepletions(
|
||||
LoggableId: depletion.RecordingId,
|
||||
Notes: note,
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, depletion.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
log.Stock = latestStockLog.Stock
|
||||
log.Stock -= log.Decrease
|
||||
} else {
|
||||
log.Stock -= log.Decrease
|
||||
}
|
||||
|
||||
if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1309,6 +1394,18 @@ func (s *recordingService) replenishRecordingEggs(
|
||||
LoggableId: egg.RecordingId,
|
||||
Notes: note,
|
||||
}
|
||||
stockLogs, err := s.StockLogRepo.GetByProductWarehouse(ctx, egg.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
log.Stock = latestStockLog.Stock
|
||||
log.Stock += log.Increase
|
||||
} else {
|
||||
log.Stock += log.Increase
|
||||
}
|
||||
|
||||
if err := s.StockLogRepo.WithTx(tx).CreateOne(ctx, log, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -826,6 +826,18 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) (
|
||||
LoggableId: approvableID,
|
||||
Notes: fmt.Sprintf("TL #%s", transfer.TransferNumber),
|
||||
}
|
||||
stockLogs, err := stockLogRepoTx.GetByProductWarehouse(c.Context(), *source.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get stock logs: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
stockLogDecrease.Stock = latestStockLog.Stock - stockLogDecrease.Decrease
|
||||
} else {
|
||||
stockLogDecrease.Stock -= stockLogDecrease.Decrease
|
||||
}
|
||||
|
||||
if err := stockLogRepoTx.CreateOne(c.Context(), stockLogDecrease, nil); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok keluar")
|
||||
}
|
||||
@@ -864,6 +876,18 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) (
|
||||
LoggableId: approvableID,
|
||||
Notes: fmt.Sprintf("TL #%s", transfer.TransferNumber),
|
||||
}
|
||||
stockLogs, err := stockLogRepoTx.GetByProductWarehouse(c.Context(), *target.ProductWarehouseId, 1)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get stock logs: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
stockLogIncrease.Stock = latestStockLog.Stock + stockLogIncrease.Increase
|
||||
} else {
|
||||
stockLogIncrease.Stock += stockLogIncrease.Increase
|
||||
}
|
||||
|
||||
if err := stockLogRepoTx.CreateOne(c.Context(), stockLogIncrease, nil); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok masuk")
|
||||
}
|
||||
|
||||
@@ -1081,10 +1081,25 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
||||
LoggableId: purchase.Id,
|
||||
Notes: receiveNote,
|
||||
}
|
||||
stockLogs, err := stockLogRepoTx.GetByProductWarehouse(ctx, entry.pwID, 1)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get stock logs: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get stock logs")
|
||||
}
|
||||
|
||||
if len(stockLogs) > 0 {
|
||||
latestStockLog := stockLogs[0]
|
||||
log.Stock = latestStockLog.Stock
|
||||
} else {
|
||||
log.Stock = 0
|
||||
}
|
||||
|
||||
if entry.delta > 0 {
|
||||
log.Increase = entry.delta
|
||||
log.Stock += log.Increase
|
||||
} else {
|
||||
log.Decrease = -entry.delta
|
||||
log.Stock -= log.Decrease
|
||||
}
|
||||
logs = append(logs, log)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user