mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-06-09 15:07:49 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f64839dfe1 | |||
| 0ff720453f |
@@ -75,9 +75,6 @@ func (u *DeliveryOrdersController) GetAll(c *fiber.Ctx) error {
|
||||
WarehouseID: uint(c.QueryInt("warehouse_id", 0)),
|
||||
SortBy: sortBy,
|
||||
SortOrder: sortOrder,
|
||||
StartDate: strings.TrimSpace(c.Query("start_date", "")),
|
||||
EndDate: strings.TrimSpace(c.Query("end_date", "")),
|
||||
FilterBy: strings.TrimSpace(c.Query("filter_by", "")),
|
||||
}
|
||||
|
||||
if isAllExcelExportRequest(c) {
|
||||
|
||||
@@ -201,6 +201,11 @@ func setMarketingExportRows(file *excelize.File, sheet string, items []dto.Marke
|
||||
for _, group := range item.DeliveryOrder {
|
||||
doNumber := safeMarketingExportText(group.DoNumber)
|
||||
|
||||
doDate := "-"
|
||||
if group.DeliveryDate != nil {
|
||||
doDate = formatMarketingExportDate(*group.DeliveryDate)
|
||||
}
|
||||
|
||||
gudang := "-"
|
||||
if group.Warehouse != nil {
|
||||
gudang = safeMarketingExportText(group.Warehouse.Name)
|
||||
@@ -210,7 +215,7 @@ func setMarketingExportRows(file *excelize.File, sheet string, items []dto.Marke
|
||||
row++
|
||||
r := strconv.Itoa(row)
|
||||
vals := map[string]interface{}{
|
||||
"A": doNumber, "B": soDate, "C": status, "D": customer, "E": salesPerson,
|
||||
"A": doNumber, "B": doDate, "C": status, "D": customer, "E": salesPerson,
|
||||
"F": "-", "G": "-", "H": gudang, "I": "-", "J": "-", "K": "-",
|
||||
"L": "-", "M": "-", "N": "-", "O": "-",
|
||||
"P": grandTotal, "Q": notes,
|
||||
@@ -246,7 +251,7 @@ func setMarketingExportRows(file *excelize.File, sheet string, items []dto.Marke
|
||||
if err := file.SetCellValue(sheet, "A"+r, doNumber); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.SetCellValue(sheet, "B"+r, soDate); err != nil {
|
||||
if err := file.SetCellValue(sheet, "B"+r, doDate); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.SetCellValue(sheet, "C"+r, status); err != nil {
|
||||
@@ -342,7 +347,7 @@ func setMarketingExportRows(file *excelize.File, sheet string, items []dto.Marke
|
||||
}
|
||||
|
||||
gudang := "-"
|
||||
if prod.ProductWarehouse != nil && prod.ProductWarehouse.Warehouse != nil {
|
||||
if prod.ProductWarehouse != nil {
|
||||
gudang = safeMarketingExportText(prod.ProductWarehouse.Warehouse.Name)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,6 @@ import (
|
||||
)
|
||||
|
||||
func TestBuildMarketingExportWorkbookHeadersAndRows(t *testing.T) {
|
||||
// DO item has soDate=2026-05-31 and deliveryDate=2026-06-01 to verify
|
||||
// the export uses soDate (not deliveryDate) in column B.
|
||||
deliveryDate := time.Date(2026, time.June, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
items := []dto.MarketingListDTO{
|
||||
{
|
||||
MarketingRelationDTO: dto.MarketingRelationDTO{
|
||||
@@ -55,22 +51,6 @@ func TestBuildMarketingExportWorkbookHeadersAndRows(t *testing.T) {
|
||||
Action: strPtr("REJECTED"),
|
||||
},
|
||||
},
|
||||
{
|
||||
MarketingRelationDTO: dto.MarketingRelationDTO{
|
||||
SoNumber: "SO-00760",
|
||||
SoDate: time.Date(2026, time.May, 31, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
Customer: customerDTO.CustomerRelationDTO{Name: "CORDELA"},
|
||||
DeliveryOrder: []dto.DeliveryGroupDTO{
|
||||
{
|
||||
DoNumber: "DO-01954",
|
||||
DeliveryDate: &deliveryDate,
|
||||
},
|
||||
},
|
||||
LatestApproval: approvalDTO.ApprovalRelationDTO{
|
||||
StepName: "Delivery Order",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
content, err := buildMarketingExportWorkbook(items)
|
||||
@@ -89,10 +69,9 @@ func TestBuildMarketingExportWorkbookHeadersAndRows(t *testing.T) {
|
||||
"B1": "Tanggal",
|
||||
"C1": "Status",
|
||||
"D1": "Customer",
|
||||
"E1": "Sales",
|
||||
"G1": "Nama Produk",
|
||||
"P1": "Grand Total",
|
||||
"Q1": "Catatan",
|
||||
"E1": "Grand Total",
|
||||
"F1": "Products",
|
||||
"G1": "Notes",
|
||||
}
|
||||
for cell, expected := range expectedHeaders {
|
||||
got, err := file.GetCellValue(marketingExportSheetName, cell)
|
||||
@@ -104,25 +83,19 @@ func TestBuildMarketingExportWorkbookHeadersAndRows(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// SO-00762: 3 products → rows 2, 3, 4
|
||||
assertCellEquals(t, file, "A2", "SO-00762")
|
||||
assertCellEquals(t, file, "B2", "22-04-2026")
|
||||
assertCellEquals(t, file, "C2", "Pengajuan")
|
||||
assertCellEquals(t, file, "D2", "AJAT")
|
||||
assertCellEquals(t, file, "G2", "PAKAN GROWING CRUMBLE 8603 MALINDO")
|
||||
assertCellEquals(t, file, "Q2", "tes")
|
||||
assertCellEquals(t, file, "E2", "Rp 5.206.200.000")
|
||||
assertCellEquals(t, file, "F2", "PAKAN GROWING CRUMBLE 8603 MALINDO, 295 GOLD PELLET")
|
||||
assertCellEquals(t, file, "G2", "tes")
|
||||
|
||||
// SO-00761 (rejected): 1 product → row 5
|
||||
assertCellEquals(t, file, "A5", "SO-00761")
|
||||
assertCellEquals(t, file, "C5", "Ditolak")
|
||||
assertCellEquals(t, file, "G5", "HS30 FOAM @20 LITER")
|
||||
assertCellEquals(t, file, "Q5", "-")
|
||||
|
||||
// DO-01954: column B must use soDate (31-05-2026), not deliveryDate (01-06-2026)
|
||||
assertCellEquals(t, file, "A6", "DO-01954")
|
||||
assertCellEquals(t, file, "B6", "31-05-2026")
|
||||
assertCellEquals(t, file, "C6", "Delivery Order")
|
||||
assertCellEquals(t, file, "D6", "CORDELA")
|
||||
assertCellEquals(t, file, "A3", "SO-00761")
|
||||
assertCellEquals(t, file, "C3", "Ditolak")
|
||||
assertCellEquals(t, file, "E3", "Rp 75.000")
|
||||
assertCellEquals(t, file, "F3", "HS30 FOAM @20 LITER")
|
||||
assertCellEquals(t, file, "G3", "-")
|
||||
}
|
||||
|
||||
func assertCellEquals(t *testing.T, file *excelize.File, cell, expected string) {
|
||||
|
||||
@@ -321,21 +321,6 @@ func (s deliveryOrdersService) GetAll(c *fiber.Ctx, params *validation.DeliveryO
|
||||
return db.Where("id = ?", params.MarketingId)
|
||||
}
|
||||
|
||||
dateStart, dateEnd, dateErr := utils.ParseDateRangeForQuery(params.StartDate, params.EndDate)
|
||||
if dateErr != nil {
|
||||
return db.Where("1 = 0")
|
||||
}
|
||||
dateCol := "marketings.so_date"
|
||||
if strings.TrimSpace(params.FilterBy) == "created_at" {
|
||||
dateCol = "marketings.created_at"
|
||||
}
|
||||
if dateStart != nil {
|
||||
db = db.Where(dateCol+" >= ?", *dateStart)
|
||||
}
|
||||
if dateEnd != nil {
|
||||
db = db.Where(dateCol+" < ?", *dateEnd)
|
||||
}
|
||||
|
||||
orderDir := "DESC"
|
||||
if params.SortOrder != "" {
|
||||
orderDir = strings.ToUpper(params.SortOrder)
|
||||
|
||||
@@ -34,9 +34,6 @@ type DeliveryOrderQuery struct {
|
||||
WarehouseID uint `query:"warehouse_id" validate:"omitempty,gt=0"`
|
||||
SortBy string `query:"sort_by" validate:"omitempty,oneof=so_number so_date status customer grand_total created_at"`
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=asc desc"`
|
||||
StartDate string `query:"start_date" validate:"omitempty,datetime=2006-01-02"`
|
||||
EndDate string `query:"end_date" validate:"omitempty,datetime=2006-01-02"`
|
||||
FilterBy string `query:"filter_by" validate:"omitempty,oneof=so_date created_at"`
|
||||
}
|
||||
|
||||
type DeliveryOrderApprove struct {
|
||||
|
||||
@@ -172,6 +172,23 @@ func (u *ChickinController) DeleteOne(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ChickinController) UpdateChickInDate(c *fiber.Ctx) error {
|
||||
req := new(validation.UpdateChickInDate)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
|
||||
if err := u.ChickinService.UpdateChickInDate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(response.Common{
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Chick in date berhasil diperbarui",
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ChickinController) Approval(c *fiber.Ctx) error {
|
||||
req := new(validation.Approve)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
@@ -18,6 +19,7 @@ type ProjectChickinRepository interface {
|
||||
GetTotalChickinQtyByProjectFlockID(ctx context.Context, projectFlockID uint) (float64, error)
|
||||
GetByProjectFlockKandangIDForUpdate(ctx context.Context, projectFlockKandangID uint) ([]entity.ProjectChickin, error)
|
||||
UpdateUsageFields(ctx context.Context, tx *gorm.DB, chickinID uint, usageQty, pendingUsageQty float64) error
|
||||
UpdateChickInDateByProjectFlockKandangID(ctx context.Context, tx *gorm.DB, pfkID uint, newDate time.Time) error
|
||||
}
|
||||
|
||||
type ChickinRepositoryImpl struct {
|
||||
@@ -134,3 +136,10 @@ func (r *ChickinRepositoryImpl) UpdateUsageFields(ctx context.Context, tx *gorm.
|
||||
"pending_usage_qty": pendingUsageQty,
|
||||
}).Error
|
||||
}
|
||||
|
||||
func (r *ChickinRepositoryImpl) UpdateChickInDateByProjectFlockKandangID(ctx context.Context, tx *gorm.DB, pfkID uint, newDate time.Time) error {
|
||||
return tx.WithContext(ctx).
|
||||
Model(&entity.ProjectChickin{}).
|
||||
Where("project_flock_kandang_id = ? AND deleted_at IS NULL", pfkID).
|
||||
Update("chick_in_date", newDate).Error
|
||||
}
|
||||
|
||||
@@ -17,8 +17,9 @@ func ChickinRoutes(v1 fiber.Router, u user.UserService, s chickin.ChickinService
|
||||
|
||||
route.Get("/", m.RequirePermissions(m.P_ChickinsGetAll), ctrl.GetAll)
|
||||
route.Post("/", m.RequirePermissions(m.P_ChickinsCreateOne), ctrl.CreateOne)
|
||||
route.Get("/:id",m.RequirePermissions(m.P_ChickinsGetOne), ctrl.GetOne)
|
||||
route.Patch("/chick-in-date", m.RequirePermissions(m.P_ChickinsCreateOne), ctrl.UpdateChickInDate)
|
||||
route.Get("/:id", m.RequirePermissions(m.P_ChickinsGetOne), ctrl.GetOne)
|
||||
// route.Patch("/:id", ctrl.UpdateOne)
|
||||
route.Delete("/:id", ctrl.DeleteOne)
|
||||
route.Post("/approvals",m.RequirePermissions(m.P_ChickinsApproval), ctrl.Approval)
|
||||
route.Post("/approvals", m.RequirePermissions(m.P_ChickinsApproval), ctrl.Approval)
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ type ChickinService interface {
|
||||
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectChickin, error)
|
||||
EnsureChickInExists(ctx context.Context, projectFlockKandangID uint) error
|
||||
UpdateChickInDate(ctx *fiber.Ctx, req *validation.UpdateChickInDate) error
|
||||
}
|
||||
|
||||
type chickinService struct {
|
||||
@@ -2110,3 +2111,38 @@ func (s chickinService) EnsureChickInExists(ctx context.Context, projectFlockKan
|
||||
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Chick in project flock belum disetujui sehingga belum dapat membuat recording")
|
||||
}
|
||||
|
||||
func (s chickinService) UpdateChickInDate(ctx *fiber.Ctx, req *validation.UpdateChickInDate) error {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newDate, err := time.Parse("2006-01-02", req.ChickInDate)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Format tanggal tidak valid, gunakan YYYY-MM-DD")
|
||||
}
|
||||
|
||||
_, err = s.ProjectflockKandangRepo.GetByID(ctx.Context(), req.ProjectFlockKandangId)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusNotFound, "Project flock kandang tidak ditemukan")
|
||||
}
|
||||
|
||||
if err := s.Repository.DB().WithContext(ctx.Context()).Transaction(func(tx *gorm.DB) error {
|
||||
if err := s.Repository.UpdateChickInDateByProjectFlockKandangID(ctx.Context(), tx, req.ProjectFlockKandangId, newDate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Exec(`
|
||||
UPDATE recordings
|
||||
SET day = GREATEST(0, (record_datetime::date - ?::date)::int),
|
||||
updated_at = NOW()
|
||||
WHERE project_flock_kandangs_id = ?
|
||||
AND deleted_at IS NULL
|
||||
`, req.ChickInDate, req.ProjectFlockKandangId).Error
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.invalidateDepreciationSnapshots(ctx.Context(), nil, []uint{req.ProjectFlockKandangId}, newDate)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,3 +27,8 @@ type Approve struct {
|
||||
ApprovableIds []uint `json:"approvable_ids" validate:"required_strict,min=1,dive,gt=0"`
|
||||
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
|
||||
}
|
||||
|
||||
type UpdateChickInDate struct {
|
||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id" validate:"required,gt=0"`
|
||||
ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user