mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
FEAT[BE] :add marketing type and conversion fields to marketing entities and services
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
-- Create sequence for transfer laying movement number
|
-- Create sequence for transfer laying movement number
|
||||||
CREATE SEQUENCE transfer_laying_seq START
|
CREATE SEQUENCE IF NOT EXISTS transfer_laying_seq START
|
||||||
WITH
|
WITH
|
||||||
1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 99999 NO CYCLE;
|
1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 99999 NO CYCLE;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- Remove columns from marketing_products
|
||||||
|
ALTER TABLE marketing_products
|
||||||
|
DROP COLUMN IF EXISTS week,
|
||||||
|
DROP COLUMN IF EXISTS weight_per_convertion,
|
||||||
|
DROP COLUMN IF EXISTS convertion_unit;
|
||||||
|
|
||||||
|
-- Remove column from marketings
|
||||||
|
ALTER TABLE marketings DROP COLUMN IF EXISTS marketing_type;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
-- Add marketing_type to marketings table
|
||||||
|
ALTER TABLE marketings
|
||||||
|
ADD COLUMN IF NOT EXISTS marketing_type VARCHAR(50);
|
||||||
|
|
||||||
|
-- Add convertion fields to marketing_products table
|
||||||
|
ALTER TABLE marketing_products
|
||||||
|
ADD COLUMN IF NOT EXISTS convertion_unit VARCHAR(20),
|
||||||
|
ADD COLUMN IF NOT EXISTS weight_per_convertion NUMERIC(15, 3),
|
||||||
|
ADD COLUMN IF NOT EXISTS week INTEGER;
|
||||||
@@ -14,6 +14,7 @@ type Marketing struct {
|
|||||||
SoDate time.Time `gorm:"type:date;not null"`
|
SoDate time.Time `gorm:"type:date;not null"`
|
||||||
SalesPersonId uint `gorm:"not null"`
|
SalesPersonId uint `gorm:"not null"`
|
||||||
Notes string `gorm:"type:text"`
|
Notes string `gorm:"type:text"`
|
||||||
|
MarketingType string `gorm:"type:varchar(50)"`
|
||||||
CreatedBy uint `gorm:"not null"`
|
CreatedBy uint `gorm:"not null"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
package entities
|
package entities
|
||||||
|
|
||||||
type MarketingProduct struct {
|
type MarketingProduct struct {
|
||||||
Id uint `gorm:"primaryKey;autoIncrement"`
|
Id uint `gorm:"primaryKey;autoIncrement"`
|
||||||
MarketingId uint `gorm:"not null"`
|
MarketingId uint `gorm:"not null"`
|
||||||
ProductWarehouseId uint `gorm:"not null"`
|
ProductWarehouseId uint `gorm:"not null"`
|
||||||
Qty float64 `gorm:"type:numeric(15,3);not null"`
|
Qty float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
UnitPrice float64 `gorm:"type:numeric(15,3);not null"`
|
ConvertionUnit *string `gorm:"type:varchar(20)"`
|
||||||
AvgWeight float64 `gorm:"type:numeric(15,3);not null"`
|
WeightPerConvertion *float64 `gorm:"type:numeric(15,3)"`
|
||||||
TotalWeight float64 `gorm:"type:numeric(15,3);not null"`
|
Week *int `gorm:"type:integer"`
|
||||||
TotalPrice float64 `gorm:"type:numeric(15,3);not null"`
|
UnitPrice float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
AvgWeight float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
TotalWeight float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
TotalPrice float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
|
||||||
Marketing Marketing `gorm:"foreignKey:MarketingId;references:Id"`
|
Marketing Marketing `gorm:"foreignKey:MarketingId;references:Id"`
|
||||||
ProductWarehouse ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
ProductWarehouse ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
||||||
|
|||||||
@@ -237,6 +237,12 @@ func (s *deliveryOrdersService) CreateOne(c *fiber.Ctx, req *validation.Delivery
|
|||||||
marketingProductRepositoryTx := marketingRepo.NewMarketingProductRepository(dbTransaction)
|
marketingProductRepositoryTx := marketingRepo.NewMarketingProductRepository(dbTransaction)
|
||||||
marketingDeliveryProductRepositoryTx := marketingRepo.NewMarketingDeliveryProductRepository(dbTransaction)
|
marketingDeliveryProductRepositoryTx := marketingRepo.NewMarketingDeliveryProductRepository(dbTransaction)
|
||||||
approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
|
approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
|
||||||
|
marketingRepoTx := marketingRepo.NewMarketingRepository(dbTransaction)
|
||||||
|
|
||||||
|
marketing, err := marketingRepoTx.GetByID(c.Context(), req.MarketingId, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch marketing")
|
||||||
|
}
|
||||||
|
|
||||||
allMarketingProducts, err := marketingProductRepositoryTx.GetByMarketingID(c.Context(), req.MarketingId)
|
allMarketingProducts, err := marketingProductRepositoryTx.GetByMarketingID(c.Context(), req.MarketingId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -283,23 +289,11 @@ func (s *deliveryOrdersService) CreateOne(c *fiber.Ctx, req *validation.Delivery
|
|||||||
itemDeliveryDate = &parsedDate
|
itemDeliveryDate = &parsedDate
|
||||||
}
|
}
|
||||||
|
|
||||||
isPakanOrOVK := false
|
|
||||||
if 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
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalWeight := requestedProduct.Qty * requestedProduct.AvgWeight
|
totalWeight := requestedProduct.Qty * requestedProduct.AvgWeight
|
||||||
var totalPrice float64
|
var totalPrice float64
|
||||||
if isPakanOrOVK {
|
if marketing.MarketingType == string(utils.MarketingTypeTrading) {
|
||||||
|
|
||||||
totalPrice = requestedProduct.Qty * requestedProduct.UnitPrice
|
totalPrice = requestedProduct.Qty * requestedProduct.UnitPrice
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
totalPrice = totalWeight * requestedProduct.UnitPrice
|
totalPrice = totalWeight * requestedProduct.UnitPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,6 +368,12 @@ func (s deliveryOrdersService) UpdateOne(c *fiber.Ctx, req *validation.DeliveryO
|
|||||||
|
|
||||||
marketingProductRepositoryTx := marketingRepo.NewMarketingProductRepository(dbTransaction)
|
marketingProductRepositoryTx := marketingRepo.NewMarketingProductRepository(dbTransaction)
|
||||||
marketingDeliveryProductRepositoryTx := marketingRepo.NewMarketingDeliveryProductRepository(dbTransaction)
|
marketingDeliveryProductRepositoryTx := marketingRepo.NewMarketingDeliveryProductRepository(dbTransaction)
|
||||||
|
marketingRepoTx := marketingRepo.NewMarketingRepository(dbTransaction)
|
||||||
|
|
||||||
|
marketing, err := marketingRepoTx.GetByID(c.Context(), id, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch marketing")
|
||||||
|
}
|
||||||
|
|
||||||
allMarketingProducts, err := marketingProductRepositoryTx.GetByMarketingID(c.Context(), id)
|
allMarketingProducts, err := marketingProductRepositoryTx.GetByMarketingID(c.Context(), id)
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
@@ -421,23 +421,11 @@ func (s deliveryOrdersService) UpdateOne(c *fiber.Ctx, req *validation.DeliveryO
|
|||||||
itemDeliveryDate = deliveryProduct.DeliveryDate
|
itemDeliveryDate = deliveryProduct.DeliveryDate
|
||||||
}
|
}
|
||||||
|
|
||||||
isPakanOrOVK := false
|
|
||||||
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
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalWeight := requestedProduct.Qty * requestedProduct.AvgWeight
|
totalWeight := requestedProduct.Qty * requestedProduct.AvgWeight
|
||||||
var totalPrice float64
|
var totalPrice float64
|
||||||
if isPakanOrOVK {
|
if marketing.MarketingType == string(utils.MarketingTypeTrading) {
|
||||||
|
|
||||||
totalPrice = requestedProduct.Qty * requestedProduct.UnitPrice
|
totalPrice = requestedProduct.Qty * requestedProduct.UnitPrice
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
totalPrice = totalWeight * requestedProduct.UnitPrice
|
totalPrice = totalWeight * requestedProduct.UnitPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,10 @@ func (s *salesOrdersService) CreateOne(c *fiber.Ctx, req *validation.Create) (*e
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !utils.IsValidMarketingType(req.MarketingType) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid marketing_type. Must be one of: AYAM, TELUR, TRADING, AYAM PULLET")
|
||||||
|
}
|
||||||
|
|
||||||
actorID, err := m.ActorIDFromContext(c)
|
actorID, err := m.ActorIDFromContext(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -115,6 +119,9 @@ func (s *salesOrdersService) CreateOne(c *fiber.Ctx, req *validation.Create) (*e
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range req.MarketingProducts {
|
for _, item := range req.MarketingProducts {
|
||||||
|
if item.ConvertionUnit != nil && !utils.IsValidConvertionUnit(*item.ConvertionUnit) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid convertion_unit. Must be one of: PETI, KG")
|
||||||
|
}
|
||||||
if err := m.EnsureProductWarehouseAccess(c, s.MarketingRepo.DB(), item.ProductWarehouseId); err != nil {
|
if err := m.EnsureProductWarehouseAccess(c, s.MarketingRepo.DB(), item.ProductWarehouseId); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -149,6 +156,7 @@ func (s *salesOrdersService) CreateOne(c *fiber.Ctx, req *validation.Create) (*e
|
|||||||
SoDate: soDate,
|
SoDate: soDate,
|
||||||
SalesPersonId: req.SalesPersonId,
|
SalesPersonId: req.SalesPersonId,
|
||||||
Notes: req.Notes,
|
Notes: req.Notes,
|
||||||
|
MarketingType: req.MarketingType,
|
||||||
CreatedBy: actorID,
|
CreatedBy: actorID,
|
||||||
}
|
}
|
||||||
if err := marketingRepoTx.CreateOne(c.Context(), marketing, nil); err != nil {
|
if err := marketingRepoTx.CreateOne(c.Context(), marketing, nil); err != nil {
|
||||||
@@ -161,10 +169,9 @@ func (s *salesOrdersService) CreateOne(c *fiber.Ctx, req *validation.Create) (*e
|
|||||||
if product.ProductWarehouseId != 0 {
|
if product.ProductWarehouseId != 0 {
|
||||||
pwIDs = append(pwIDs, product.ProductWarehouseId)
|
pwIDs = append(pwIDs, product.ProductWarehouseId)
|
||||||
}
|
}
|
||||||
if err := s.createMarketingProductWithDelivery(c.Context(), marketing.Id, product, marketingProductRepoTx, invDeliveryRepoTx); err != nil {
|
if err := s.createMarketingProductWithDelivery(c.Context(), marketing.Id, marketing.MarketingType, product, marketingProductRepoTx, invDeliveryRepoTx); err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create marketing product")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create marketing product")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if err := commonSvc.EnsureProjectFlockNotClosedForProductWarehouses(c.Context(), s.MarketingRepo.DB(), pwIDs); err != nil {
|
if err := commonSvc.EnsureProjectFlockNotClosedForProductWarehouses(c.Context(), s.MarketingRepo.DB(), pwIDs); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -207,6 +214,10 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.MarketingType != "" && !utils.IsValidMarketingType(req.MarketingType) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid marketing_type. Must be one of: AYAM, TELUR, TRADING, AYAM PULLET")
|
||||||
|
}
|
||||||
|
|
||||||
if err := m.EnsureMarketingAccess(c, s.MarketingRepo.DB(), id); err != nil {
|
if err := m.EnsureMarketingAccess(c, s.MarketingRepo.DB(), id); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -234,6 +245,9 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u
|
|||||||
|
|
||||||
if len(req.MarketingProducts) > 0 {
|
if len(req.MarketingProducts) > 0 {
|
||||||
for _, item := range req.MarketingProducts {
|
for _, item := range req.MarketingProducts {
|
||||||
|
if item.ConvertionUnit != nil && !utils.IsValidConvertionUnit(*item.ConvertionUnit) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid convertion_unit. Must be one of: PETI, KG")
|
||||||
|
}
|
||||||
if err := m.EnsureProductWarehouseAccess(c, s.MarketingRepo.DB(), item.ProductWarehouseId); err != nil {
|
if err := m.EnsureProductWarehouseAccess(c, s.MarketingRepo.DB(), item.ProductWarehouseId); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -281,6 +295,9 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u
|
|||||||
if req.Notes != "" {
|
if req.Notes != "" {
|
||||||
updateBody["notes"] = req.Notes
|
updateBody["notes"] = req.Notes
|
||||||
}
|
}
|
||||||
|
if req.MarketingType != "" {
|
||||||
|
updateBody["marketing_type"] = req.MarketingType
|
||||||
|
}
|
||||||
|
|
||||||
if len(updateBody) > 0 {
|
if len(updateBody) > 0 {
|
||||||
if err := marketingRepoTx.PatchOne(c.Context(), id, updateBody, nil); err != nil {
|
if err := marketingRepoTx.PatchOne(c.Context(), id, updateBody, nil); err != nil {
|
||||||
@@ -306,31 +323,17 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u
|
|||||||
reqByPW[rp.ProductWarehouseId] = rp
|
reqByPW[rp.ProductWarehouseId] = rp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
marketing, err := marketingRepoTx.GetByID(c.Context(), id, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch marketing")
|
||||||
|
}
|
||||||
|
|
||||||
for _, rp := range req.MarketingProducts {
|
for _, rp := range req.MarketingProducts {
|
||||||
if old, ok := oldByPW[rp.ProductWarehouseId]; ok {
|
if old, ok := oldByPW[rp.ProductWarehouseId]; ok {
|
||||||
|
|
||||||
// Get product untuk cek flag PAKAN atau OVK
|
|
||||||
productWarehouse, err := s.ProductWarehouseRepo.GetByID(c.Context(), rp.ProductWarehouseId, func(db *gorm.DB) *gorm.DB {
|
|
||||||
return db.Preload("Product.Flags")
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cek apakah product punya flag PAKAN atau OVK
|
|
||||||
isPakanOrOVK := false
|
|
||||||
if productWarehouse.Product.Id != 0 && len(productWarehouse.Product.Flags) > 0 {
|
|
||||||
for _, flag := range productWarehouse.Product.Flags {
|
|
||||||
if flag.Name == string(utils.FlagPakan) || flag.Name == string(utils.FlagOVK) {
|
|
||||||
isPakanOrOVK = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalWeight := rp.Qty * rp.AvgWeight
|
totalWeight := rp.Qty * rp.AvgWeight
|
||||||
var totalPrice float64
|
var totalPrice float64
|
||||||
if isPakanOrOVK {
|
if marketing.MarketingType == string(utils.MarketingTypeTrading) {
|
||||||
totalPrice = rp.Qty * rp.UnitPrice
|
totalPrice = rp.Qty * rp.UnitPrice
|
||||||
} else {
|
} else {
|
||||||
totalPrice = totalWeight * rp.UnitPrice
|
totalPrice = totalWeight * rp.UnitPrice
|
||||||
@@ -340,7 +343,6 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u
|
|||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to check delivery product")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to check delivery product")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && deliveryProduct.Id != 0 {
|
if err == nil && deliveryProduct.Id != 0 {
|
||||||
oldQty := old.Qty
|
oldQty := old.Qty
|
||||||
newQty := rp.Qty
|
newQty := rp.Qty
|
||||||
@@ -363,12 +365,15 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateBody := map[string]any{
|
updateBody := map[string]any{
|
||||||
"product_warehouse_id": rp.ProductWarehouseId,
|
"product_warehouse_id": rp.ProductWarehouseId,
|
||||||
"qty": rp.Qty,
|
"qty": rp.Qty,
|
||||||
"unit_price": rp.UnitPrice,
|
"unit_price": rp.UnitPrice,
|
||||||
"avg_weight": rp.AvgWeight,
|
"avg_weight": rp.AvgWeight,
|
||||||
"total_weight": totalWeight,
|
"total_weight": totalWeight,
|
||||||
"total_price": totalPrice,
|
"total_price": totalPrice,
|
||||||
|
"convertion_unit": rp.ConvertionUnit,
|
||||||
|
"weight_per_convertion": rp.WeightPerConvertion,
|
||||||
|
"week": rp.Week,
|
||||||
}
|
}
|
||||||
if err := marketingProductRepoTx.PatchOne(c.Context(), old.Id, updateBody, nil); err != nil {
|
if err := marketingProductRepoTx.PatchOne(c.Context(), old.Id, updateBody, nil); err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update marketing product")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update marketing product")
|
||||||
@@ -391,7 +396,7 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := s.createMarketingProductWithDelivery(c.Context(), id, rp, marketingProductRepoTx, invDeliveryRepoTx); err != nil {
|
if err := s.createMarketingProductWithDelivery(c.Context(), id, marketing.MarketingType, rp, marketingProductRepoTx, invDeliveryRepoTx); err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create marketing product")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create marketing product")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -399,7 +404,6 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u
|
|||||||
|
|
||||||
for _, old := range oldProducts {
|
for _, old := range oldProducts {
|
||||||
if _, ok := reqByPW[old.ProductWarehouseId]; !ok {
|
if _, ok := reqByPW[old.ProductWarehouseId]; !ok {
|
||||||
|
|
||||||
deliveryProduct, err := invDeliveryRepoTx.GetByMarketingProductID(c.Context(), old.Id)
|
deliveryProduct, err := invDeliveryRepoTx.GetByMarketingProductID(c.Context(), old.Id)
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to check existing delivery product")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to check existing delivery product")
|
||||||
@@ -682,45 +686,27 @@ func (s salesOrdersService) Approval(c *fiber.Ctx, req *validation.Approve) ([]e
|
|||||||
return updated, nil
|
return updated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *salesOrdersService) createMarketingProductWithDelivery(ctx context.Context, marketingId uint, rp validation.CreateMarketingProduct, marketingProductRepo repository.MarketingProductRepository, invDeliveryRepo repository.MarketingDeliveryProductRepository) error {
|
func (s *salesOrdersService) createMarketingProductWithDelivery(ctx context.Context, marketingId uint, marketingType string, rp validation.CreateMarketingProduct, marketingProductRepo repository.MarketingProductRepository, invDeliveryRepo repository.MarketingDeliveryProductRepository) error {
|
||||||
|
|
||||||
// Get product untuk cek flag PAKAN atau OVK
|
|
||||||
productWarehouse, err := s.ProductWarehouseRepo.GetByID(ctx, rp.ProductWarehouseId, func(db *gorm.DB) *gorm.DB {
|
|
||||||
return db.Preload("Product.Flags")
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cek apakah product punya flag PAKAN atau OVK
|
|
||||||
isPakanOrOVK := false
|
|
||||||
if productWarehouse.Product.Id != 0 && len(productWarehouse.Product.Flags) > 0 {
|
|
||||||
for _, flag := range productWarehouse.Product.Flags {
|
|
||||||
if flag.Name == string(utils.FlagPakan) || flag.Name == string(utils.FlagOVK) {
|
|
||||||
isPakanOrOVK = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalWeight := rp.Qty * rp.AvgWeight
|
totalWeight := rp.Qty * rp.AvgWeight
|
||||||
var totalPrice float64
|
var totalPrice float64
|
||||||
if isPakanOrOVK {
|
if marketingType == string(utils.MarketingTypeTrading) {
|
||||||
// PAKAN atau OVK: qty × unit_price
|
|
||||||
totalPrice = rp.Qty * rp.UnitPrice
|
totalPrice = rp.Qty * rp.UnitPrice
|
||||||
} else {
|
} else {
|
||||||
// Produk lain: total_weight × unit_price
|
|
||||||
totalPrice = totalWeight * rp.UnitPrice
|
totalPrice = totalWeight * rp.UnitPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
marketingProduct := &entity.MarketingProduct{
|
marketingProduct := &entity.MarketingProduct{
|
||||||
MarketingId: marketingId,
|
MarketingId: marketingId,
|
||||||
ProductWarehouseId: rp.ProductWarehouseId,
|
ProductWarehouseId: rp.ProductWarehouseId,
|
||||||
Qty: rp.Qty,
|
Qty: rp.Qty,
|
||||||
UnitPrice: rp.UnitPrice,
|
UnitPrice: rp.UnitPrice,
|
||||||
AvgWeight: rp.AvgWeight,
|
AvgWeight: rp.AvgWeight,
|
||||||
TotalWeight: totalWeight,
|
TotalWeight: totalWeight,
|
||||||
TotalPrice: totalPrice,
|
TotalPrice: totalPrice,
|
||||||
|
ConvertionUnit: rp.ConvertionUnit,
|
||||||
|
WeightPerConvertion: rp.WeightPerConvertion,
|
||||||
|
Week: rp.Week,
|
||||||
}
|
}
|
||||||
if err := marketingProductRepo.CreateOne(ctx, marketingProduct, nil); err != nil {
|
if err := marketingProductRepo.CreateOne(ctx, marketingProduct, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -5,15 +5,19 @@ type Create struct {
|
|||||||
SalesPersonId uint `json:"sales_person_id" validate:"required,gt=0"`
|
SalesPersonId uint `json:"sales_person_id" validate:"required,gt=0"`
|
||||||
Date string `json:"date" validate:"required,datetime=2006-01-02"`
|
Date string `json:"date" validate:"required,datetime=2006-01-02"`
|
||||||
Notes string `json:"notes" validate:"omitempty,max=500"`
|
Notes string `json:"notes" validate:"omitempty,max=500"`
|
||||||
|
MarketingType string `json:"marketing_type" validate:"required,min=1,max=50"`
|
||||||
MarketingProducts []CreateMarketingProduct `json:"marketing_products" validate:"required,min=1,dive"`
|
MarketingProducts []CreateMarketingProduct `json:"marketing_products" validate:"required,min=1,dive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateMarketingProduct struct {
|
type CreateMarketingProduct struct {
|
||||||
VehicleNumber string `json:"vehicle_number" validate:"required,min=1,max=50"`
|
VehicleNumber string `json:"vehicle_number" validate:"required,min=1,max=50"`
|
||||||
ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,gt=0"`
|
ConvertionUnit *string `json:"convertion_unit" validate:"omitempty,min=1,max=20"`
|
||||||
UnitPrice float64 `json:"unit_price" validate:"required,gt=0"`
|
WeightPerConvertion *float64 `json:"weight_per_convertion" validate:"omitempty,gt=0"`
|
||||||
Qty float64 `json:"qty" validate:"required,gt=0"`
|
Week *int `json:"week" validate:"omitempty,gt=0"`
|
||||||
AvgWeight float64 `json:"avg_weight" validate:"required,gt=0"`
|
ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,gt=0"`
|
||||||
|
UnitPrice float64 `json:"unit_price" validate:"required,gt=0"`
|
||||||
|
Qty float64 `json:"qty" validate:"required,gt=0"`
|
||||||
|
AvgWeight float64 `json:"avg_weight" validate:"required,gt=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
@@ -21,6 +25,7 @@ type Update struct {
|
|||||||
SalesPersonId uint `json:"sales_person_id" validate:"omitempty,gt=0"`
|
SalesPersonId uint `json:"sales_person_id" validate:"omitempty,gt=0"`
|
||||||
Date string `json:"date" validate:"omitempty,datetime=2006-01-02"`
|
Date string `json:"date" validate:"omitempty,datetime=2006-01-02"`
|
||||||
Notes string `json:"notes" validate:"omitempty,max=500"`
|
Notes string `json:"notes" validate:"omitempty,max=500"`
|
||||||
|
MarketingType string `json:"marketing_type" validate:"omitempty,min=1,max=50"`
|
||||||
MarketingProducts []CreateMarketingProduct `json:"marketing_products" validate:"omitempty,min=1,dive"`
|
MarketingProducts []CreateMarketingProduct `json:"marketing_products" validate:"omitempty,min=1,dive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,6 +212,30 @@ const (
|
|||||||
KandangStatusActive KandangStatus = "ACTIVE"
|
KandangStatusActive KandangStatus = "ACTIVE"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Marketing Type
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
type MarketingType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MarketingTypeAyam MarketingType = "AYAM"
|
||||||
|
MarketingTypeTelur MarketingType = "TELUR"
|
||||||
|
MarketingTypeTrading MarketingType = "TRADING"
|
||||||
|
MarketingTypeAyamPullet MarketingType = "AYAM PULLET"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Convertion Unit
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
type ConvertionUnit string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConvertionUnitPeti ConvertionUnit = "PETI"
|
||||||
|
ConvertionUnitKG ConvertionUnit = "KG"
|
||||||
|
)
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// ProjectFlockCategory
|
// ProjectFlockCategory
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
@@ -609,6 +633,22 @@ func IsValidPaymentParty(v string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsValidMarketingType(v string) bool {
|
||||||
|
switch MarketingType(v) {
|
||||||
|
case MarketingTypeAyam, MarketingTypeTelur, MarketingTypeTrading, MarketingTypeAyamPullet:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidConvertionUnit(v string) bool {
|
||||||
|
switch ConvertionUnit(v) {
|
||||||
|
case ConvertionUnitPeti, ConvertionUnitKG:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// example use
|
// example use
|
||||||
|
|
||||||
// Recording helper
|
// Recording helper
|
||||||
|
|||||||
Reference in New Issue
Block a user