feat/BE/US-304/TASK-292,293-restriction expense not finish and stock not used,add status project flock completed, fix dto purchase, fix dto nonstock supplier, purchase

This commit is contained in:
ragilap
2025-12-10 16:30:17 +07:00
parent 0fbf04fc1d
commit 2b6ba3a41d
4 changed files with 69 additions and 31 deletions
+1
View File
@@ -23,6 +23,7 @@ type PurchaseItem struct {
ExpenseNonstockId *uint64 ExpenseNonstockId *uint64
// Relations // Relations
ExpenseNonstock *ExpenseNonstock `gorm:"foreignKey:ExpenseNonstockId;references:Id"`
Purchase *Purchase `gorm:"foreignKey:PurchaseId;references:Id"` Purchase *Purchase `gorm:"foreignKey:PurchaseId;references:Id"`
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"`
@@ -1,11 +1,11 @@
package dto package dto
import ( import (
"time"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities" entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto"
uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto" uomDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/uoms/dto"
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
"time"
) )
// === DTO Structs === // === DTO Structs ===
@@ -18,13 +18,14 @@ type NonstockRelationDTO struct {
} }
type NonstockListDTO struct { type NonstockListDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Flags []string `json:"flags"` Flags []string `json:"flags"`
Uom *uomDTO.UomRelationDTO `json:"uom"` Uom *uomDTO.UomRelationDTO `json:"uom"`
CreatedUser *userDTO.UserRelationDTO `json:"created_user"` Suppliers []supplierDTO.SupplierRelationDTO `json:"suppliers,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
UpdatedAt time.Time `json:"updated_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} }
type NonstockDetailDTO struct { type NonstockDetailDTO struct {
@@ -76,6 +77,7 @@ func ToNonstockListDTO(e entity.Nonstock) NonstockListDTO {
Name: e.Name, Name: e.Name,
Flags: flags, Flags: flags,
Uom: uomRef, Uom: uomRef,
Suppliers: toNonstockSupplierDTOs(e.NonstockSuppliers),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
CreatedUser: createdUser, CreatedUser: createdUser,
@@ -95,3 +97,23 @@ func ToNonstockDetailDTO(e entity.Nonstock) NonstockDetailDTO {
NonstockListDTO: ToNonstockListDTO(e), NonstockListDTO: ToNonstockListDTO(e),
} }
} }
func toNonstockSupplierDTOs(relations []entity.NonstockSupplier) []supplierDTO.SupplierRelationDTO {
if len(relations) == 0 {
return nil
}
result := make([]supplierDTO.SupplierRelationDTO, 0, len(relations))
for _, relation := range relations {
if relation.Supplier.Id == 0 {
continue
}
result = append(result, supplierDTO.ToSupplierRelationDTO(relation.Supplier))
}
if len(result) == 0 {
return nil
}
return result
}
+16 -2
View File
@@ -42,7 +42,6 @@ type PurchaseDetailDTO struct {
LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval"` LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval"`
} }
type PurchaseItemDTO struct { type PurchaseItemDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
ProductID uint `json:"product_id"` ProductID uint `json:"product_id"`
@@ -59,9 +58,10 @@ type PurchaseItemDTO struct {
TravelNumber *string `json:"travel_number"` TravelNumber *string `json:"travel_number"`
TravelDocumentPath *string `json:"travel_document_path"` TravelDocumentPath *string `json:"travel_document_path"`
VehicleNumber *string `json:"vehicle_number"` VehicleNumber *string `json:"vehicle_number"`
TransportPerItem *float64 `json:"transport_per_item,omitempty"`
ExpeditionVendor *supplierDTO.SupplierRelationDTO `json:"expedition_vendor,omitempty"`
} }
func ToPurchaseRelationDTO(p *entity.Purchase) PurchaseRelationDTO { func ToPurchaseRelationDTO(p *entity.Purchase) PurchaseRelationDTO {
return PurchaseRelationDTO{ return PurchaseRelationDTO{
Id: p.Id, Id: p.Id,
@@ -107,6 +107,20 @@ func ToPurchaseItemDTO(item entity.PurchaseItem) PurchaseItemDTO {
dto.Warehouse = &summary dto.Warehouse = &summary
} }
if item.ExpenseNonstock != nil {
priceCopy := item.ExpenseNonstock.Price
dto.TransportPerItem = &priceCopy
if item.ExpenseNonstock.Expense != nil {
exp := item.ExpenseNonstock.Expense
if exp.Supplier != nil && exp.Supplier.Id != 0 {
supplierSummary := supplierDTO.ToSupplierRelationDTO(*exp.Supplier)
dto.ExpeditionVendor = &supplierSummary
}
}
}
return dto return dto
} }
@@ -110,7 +110,10 @@ func (s *purchaseService) withRelations(db *gorm.DB) *gorm.DB {
Preload("Items.Product.Flags"). Preload("Items.Product.Flags").
Preload("Items.Warehouse.Area"). Preload("Items.Warehouse.Area").
Preload("Items.Warehouse.Location"). Preload("Items.Warehouse.Location").
Preload("Items.ProductWarehouse") Preload("Items.ProductWarehouse").
Preload("Items.ExpenseNonstock").
Preload("Items.ExpenseNonstock.Expense").
Preload("Items.ExpenseNonstock.Expense.Supplier")
} }
func (s *purchaseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.Purchase, int64, error) { func (s *purchaseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.Purchase, int64, error) {
@@ -319,8 +322,8 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase
purchase := &entity.Purchase{ purchase := &entity.Purchase{
SupplierId: uint(req.SupplierID), SupplierId: uint(req.SupplierID),
// DueDate: dueDate, // DueDate: dueDate,
Notes: req.Notes, Notes: req.Notes,
CreatedBy: uint(actorID), CreatedBy: uint(actorID),
} }
items := make([]*entity.PurchaseItem, 0, len(aggregated)) items := make([]*entity.PurchaseItem, 0, len(aggregated))
@@ -432,7 +435,7 @@ func (s *purchaseService) ApproveStaffPurchase(c *fiber.Ctx, id uint, req *valid
syncReceiving := !isInitialApproval && hasReceivingData syncReceiving := !isInitialApproval && hasReceivingData
if len(req.Items) == 0 { if action == entity.ApprovalActionApproved && len(req.Items) == 0 {
return nil, utils.BadRequest("Items must not be empty for staff approval") return nil, utils.BadRequest("Items must not be empty for staff approval")
} }
@@ -1397,21 +1400,21 @@ func (s *purchaseService) loadPurchase(
} }
func collectPFKIDsFromPurchase(p *entity.Purchase) []uint { func collectPFKIDsFromPurchase(p *entity.Purchase) []uint {
seen := make(map[uint]struct{}) seen := make(map[uint]struct{})
ids := make([]uint, 0) ids := make([]uint, 0)
for _, item := range p.Items { for _, item := range p.Items {
if item.ProjectFlockKandangId == nil || *item.ProjectFlockKandangId == 0 { if item.ProjectFlockKandangId == nil || *item.ProjectFlockKandangId == 0 {
continue continue
} }
id := uint(*item.ProjectFlockKandangId) id := uint(*item.ProjectFlockKandangId)
if _, ok := seen[id]; ok { if _, ok := seen[id]; ok {
continue continue
} }
seen[id] = struct{}{} seen[id] = struct{}{}
ids = append(ids, id) ids = append(ids, id)
} }
return ids return ids
} }
func (s *purchaseService) ensureProjectFlockNotClosedForPurchase( func (s *purchaseService) ensureProjectFlockNotClosedForPurchase(
ctx context.Context, ctx context.Context,
@@ -1429,5 +1432,3 @@ func (s *purchaseService) ensureProjectFlockNotClosedForPurchase(
return commonSvc.EnsureProjectFlockNotClosedForProductWarehouses(ctx, db, pfkIDs) return commonSvc.EnsureProjectFlockNotClosedForProductWarehouses(ctx, db, pfkIDs)
} }