mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat(BE-278): unrestrict feat warehouse purchase,adding purchase upload document
This commit is contained in:
@@ -44,6 +44,7 @@ const (
|
|||||||
P_ReportExpenseGetAll = "lti.repport.expense.list"
|
P_ReportExpenseGetAll = "lti.repport.expense.list"
|
||||||
P_ReportDeliveryGetAll = "lti.repport.delivery.list"
|
P_ReportDeliveryGetAll = "lti.repport.delivery.list"
|
||||||
P_ReportPurchaseSupplierGetAll = "lti.repport.purchasesupplier.list"
|
P_ReportPurchaseSupplierGetAll = "lti.repport.purchasesupplier.list"
|
||||||
|
P_ReportHppPerKandangGetAll = "lti.repport.gethppperkandang.list"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -214,21 +214,19 @@ func (s *expenseService) CreateOne(c *fiber.Ctx, req *validation.Create) (*expen
|
|||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get active project flocks for location")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get active project flocks for location")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(activeProjectFlocks) == 0 {
|
if len(activeProjectFlocks) > 0 {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "No active project flocks found for this location")
|
projectFlockIDs := make([]uint64, len(activeProjectFlocks))
|
||||||
}
|
for i, pf := range activeProjectFlocks {
|
||||||
|
projectFlockIDs[i] = uint64(pf.Id)
|
||||||
|
}
|
||||||
|
|
||||||
projectFlockIDs := make([]uint64, len(activeProjectFlocks))
|
projectFlockIdsJSON, err := json.Marshal(projectFlockIDs)
|
||||||
for i, pf := range activeProjectFlocks {
|
if err != nil {
|
||||||
projectFlockIDs[i] = uint64(pf.Id)
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to marshal project_flock_ids")
|
||||||
|
}
|
||||||
|
jsonStr := string(projectFlockIdsJSON)
|
||||||
|
projectFlockIdJSON = &jsonStr
|
||||||
}
|
}
|
||||||
|
|
||||||
projectFlockIdsJSON, err := json.Marshal(projectFlockIDs)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to marshal project_flock_ids")
|
|
||||||
}
|
|
||||||
jsonStr := string(projectFlockIdsJSON)
|
|
||||||
projectFlockIdJSON = &jsonStr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expense = &entity.Expense{
|
expense = &entity.Expense{
|
||||||
|
|||||||
+25
@@ -199,6 +199,31 @@ func (r *ProductWarehouseRepositoryImpl) CleanupEmpty(ctx context.Context, affec
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var inUseIDs []uint
|
||||||
|
if err := r.DB().WithContext(ctx).
|
||||||
|
Model(&entity.PurchaseItem{}).
|
||||||
|
Where("product_warehouse_id IN ?", emptyIDs).
|
||||||
|
Distinct().
|
||||||
|
Pluck("product_warehouse_id", &inUseIDs).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(inUseIDs) > 0 {
|
||||||
|
inUse := make(map[uint]struct{}, len(inUseIDs))
|
||||||
|
for _, id := range inUseIDs {
|
||||||
|
inUse[id] = struct{}{}
|
||||||
|
}
|
||||||
|
filtered := make([]uint, 0, len(emptyIDs))
|
||||||
|
for _, id := range emptyIDs {
|
||||||
|
if _, exists := inUse[id]; !exists {
|
||||||
|
filtered = append(filtered, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emptyIDs = filtered
|
||||||
|
}
|
||||||
|
if len(emptyIDs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := r.DB().WithContext(ctx).
|
if err := r.DB().WithContext(ctx).
|
||||||
Model(&entity.PurchaseItem{}).
|
Model(&entity.PurchaseItem{}).
|
||||||
Where("product_warehouse_id IN ?", emptyIDs).
|
Where("product_warehouse_id IN ?", emptyIDs).
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -24,13 +25,13 @@ func NewPurchaseController(s service.PurchaseService) *PurchaseController {
|
|||||||
|
|
||||||
func (ctrl *PurchaseController) GetAll(c *fiber.Ctx) error {
|
func (ctrl *PurchaseController) GetAll(c *fiber.Ctx) error {
|
||||||
query := &validation.Query{
|
query := &validation.Query{
|
||||||
Page: c.QueryInt("page", 1),
|
Page: c.QueryInt("page", 1),
|
||||||
Limit: c.QueryInt("limit", 10),
|
Limit: c.QueryInt("limit", 10),
|
||||||
CreatedFrom: strings.TrimSpace(c.Query("created_from")),
|
CreatedFrom: strings.TrimSpace(c.Query("created_from")),
|
||||||
CreatedTo: strings.TrimSpace(c.Query("created_to")),
|
CreatedTo: strings.TrimSpace(c.Query("created_to")),
|
||||||
SupplierID: uint(c.QueryInt("supplier_id", 0)),
|
SupplierID: uint(c.QueryInt("supplier_id", 0)),
|
||||||
AreaID: uint(c.QueryInt("area_id", 0)),
|
AreaID: uint(c.QueryInt("area_id", 0)),
|
||||||
LocationID: uint(c.QueryInt("location_id", 0)),
|
LocationID: uint(c.QueryInt("location_id", 0)),
|
||||||
ProductCategoryID: uint(c.QueryInt("product_category_id", 0)),
|
ProductCategoryID: uint(c.QueryInt("product_category_id", 0)),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +87,6 @@ func (ctrl *PurchaseController) CreateOne(c *fiber.Ctx) error {
|
|||||||
if err := c.BodyParser(req); err != nil {
|
if err := c.BodyParser(req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := ctrl.service.CreateOne(c, req)
|
result, err := ctrl.service.CreateOne(c, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -161,10 +161,26 @@ func (ctrl *PurchaseController) ReceiveProducts(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := new(validation.ReceivePurchaseRequest)
|
req := new(validation.ReceivePurchaseRequest)
|
||||||
if err := c.BodyParser(req); err != nil {
|
form, err := c.MultipartForm()
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form")
|
||||||
|
}
|
||||||
|
req.Action = c.FormValue("action")
|
||||||
|
if notes := strings.TrimSpace(c.FormValue("notes")); notes != "" {
|
||||||
|
req.Notes = ¬es
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemsJSON := c.FormValue("items")
|
||||||
|
if strings.TrimSpace(itemsJSON) != "" {
|
||||||
|
if err := json.Unmarshal([]byte(itemsJSON), &req.Items); err != nil {
|
||||||
|
var singleItem validation.ReceivePurchaseItemRequest
|
||||||
|
if err := json.Unmarshal([]byte(itemsJSON), &singleItem); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid items JSON")
|
||||||
|
}
|
||||||
|
req.Items = []validation.ReceivePurchaseItemRequest{singleItem}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.TravelDocuments = form.File["documents"]
|
||||||
result, err := ctrl.service.ReceiveProducts(c, uint(id), req)
|
result, err := ctrl.service.ReceiveProducts(c, uint(id), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ func (PurchaseModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate
|
|||||||
approvalService,
|
approvalService,
|
||||||
expenseBridge,
|
expenseBridge,
|
||||||
fifoService,
|
fifoService,
|
||||||
|
documentSvc,
|
||||||
)
|
)
|
||||||
|
|
||||||
userRepo := rUser.NewUserRepository(db)
|
userRepo := rUser.NewUserRepository(db)
|
||||||
|
|||||||
@@ -394,9 +394,13 @@ func (b *expenseBridge) OnItemsReceived(c *fiber.Ctx, purchaseID uint, updates [
|
|||||||
}
|
}
|
||||||
if kandangID != nil {
|
if kandangID != nil {
|
||||||
updateBody["kandang_id"] = uint64(*kandangID)
|
updateBody["kandang_id"] = uint64(*kandangID)
|
||||||
|
} else {
|
||||||
|
updateBody["kandang_id"] = nil
|
||||||
}
|
}
|
||||||
if projectFK != nil {
|
if projectFK != nil {
|
||||||
updateBody["project_flock_kandang_id"] = uint64(*projectFK)
|
updateBody["project_flock_kandang_id"] = uint64(*projectFK)
|
||||||
|
} else {
|
||||||
|
updateBody["project_flock_kandang_id"] = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.db.WithContext(ctx).
|
if err := b.db.WithContext(ctx).
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"mime/multipart"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ type purchaseService struct {
|
|||||||
ApprovalSvc commonSvc.ApprovalService
|
ApprovalSvc commonSvc.ApprovalService
|
||||||
ExpenseBridge PurchaseExpenseBridge
|
ExpenseBridge PurchaseExpenseBridge
|
||||||
FifoSvc commonSvc.FifoService
|
FifoSvc commonSvc.FifoService
|
||||||
|
DocumentSvc commonSvc.DocumentService
|
||||||
approvalWorkflow approvalutils.ApprovalWorkflowKey
|
approvalWorkflow approvalutils.ApprovalWorkflowKey
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +78,7 @@ func NewPurchaseService(
|
|||||||
approvalSvc commonSvc.ApprovalService,
|
approvalSvc commonSvc.ApprovalService,
|
||||||
expenseBridge PurchaseExpenseBridge,
|
expenseBridge PurchaseExpenseBridge,
|
||||||
fifoSvc commonSvc.FifoService,
|
fifoSvc commonSvc.FifoService,
|
||||||
|
documentSvc commonSvc.DocumentService,
|
||||||
) PurchaseService {
|
) PurchaseService {
|
||||||
return &purchaseService{
|
return &purchaseService{
|
||||||
Log: utils.Log,
|
Log: utils.Log,
|
||||||
@@ -89,6 +92,7 @@ func NewPurchaseService(
|
|||||||
ApprovalSvc: approvalSvc,
|
ApprovalSvc: approvalSvc,
|
||||||
ExpenseBridge: expenseBridge,
|
ExpenseBridge: expenseBridge,
|
||||||
FifoSvc: fifoSvc,
|
FifoSvc: fifoSvc,
|
||||||
|
DocumentSvc: documentSvc,
|
||||||
approvalWorkflow: utils.ApprovalWorkflowPurchase,
|
approvalWorkflow: utils.ApprovalWorkflowPurchase,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,9 +619,7 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
|||||||
if err := s.Validate.Struct(req); err != nil {
|
if err := s.Validate.Struct(req); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := c.Context()
|
ctx := c.Context()
|
||||||
|
|
||||||
action, err := parseApprovalActionInput(req.Action)
|
action, err := parseApprovalActionInput(req.Action)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -664,6 +666,30 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
|||||||
return updated, nil
|
return updated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == entity.ApprovalActionApproved && len(req.TravelDocuments) > 0 {
|
||||||
|
if len(req.TravelDocuments) > len(req.Items) {
|
||||||
|
return nil, utils.BadRequest("Travel documents exceed total receiving items")
|
||||||
|
}
|
||||||
|
for idx, file := range req.TravelDocuments {
|
||||||
|
if file == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if idx >= len(req.Items) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
itemID := req.Items[idx].PurchaseItemID
|
||||||
|
if itemID == 0 {
|
||||||
|
return nil, utils.BadRequest("Purchase item id is required for travel document upload")
|
||||||
|
}
|
||||||
|
uploadedURL, err := s.uploadTravelDocument(ctx, actorID, itemID, file)
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to upload travel document for item %d: %+v", itemID, err)
|
||||||
|
return nil, utils.Internal("Failed to upload travel document")
|
||||||
|
}
|
||||||
|
req.Items[idx].TravelDocumentPath = &uploadedURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
itemMap := make(map[uint]*entity.PurchaseItem, len(purchase.Items))
|
itemMap := make(map[uint]*entity.PurchaseItem, len(purchase.Items))
|
||||||
for i := range purchase.Items {
|
for i := range purchase.Items {
|
||||||
itemMap[purchase.Items[i].Id] = &purchase.Items[i]
|
itemMap[purchase.Items[i].Id] = &purchase.Items[i]
|
||||||
@@ -807,32 +833,20 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
|||||||
for _, prep := range prepared {
|
for _, prep := range prepared {
|
||||||
item := prep.item
|
item := prep.item
|
||||||
|
|
||||||
var oldPWID *uint
|
|
||||||
if item.ProductWarehouseId != nil {
|
|
||||||
idCopy := uint(*item.ProductWarehouseId)
|
|
||||||
oldPWID = &idCopy
|
|
||||||
}
|
|
||||||
|
|
||||||
var newPWID *uint
|
var newPWID *uint
|
||||||
clearPW := false
|
|
||||||
|
|
||||||
// Always ensure PW when qty > 0 so stockable has target.
|
// Always ensure PW after receiving so linkage stays stable.
|
||||||
if prep.receivedQty > 0 {
|
pwID, err := pwRepoTx.EnsureProductWarehouse(
|
||||||
pwID, err := pwRepoTx.EnsureProductWarehouse(
|
c.Context(),
|
||||||
c.Context(),
|
uint(item.ProductId),
|
||||||
uint(item.ProductId),
|
prep.warehouseID,
|
||||||
prep.warehouseID,
|
item.ProjectFlockKandangId,
|
||||||
item.ProjectFlockKandangId,
|
purchase.CreatedBy,
|
||||||
purchase.CreatedBy,
|
)
|
||||||
)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
newPWID = &pwID
|
|
||||||
} else if oldPWID != nil {
|
|
||||||
newPWID = oldPWID
|
|
||||||
clearPW = true
|
|
||||||
}
|
}
|
||||||
|
newPWID = &pwID
|
||||||
|
|
||||||
deltaQty := prep.receivedQty - item.TotalQty
|
deltaQty := prep.receivedQty - item.TotalQty
|
||||||
switch {
|
switch {
|
||||||
@@ -857,7 +871,7 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
|||||||
VehicleNumber: prep.payload.VehicleNumber,
|
VehicleNumber: prep.payload.VehicleNumber,
|
||||||
ReceivedQty: &qtyCopy,
|
ReceivedQty: &qtyCopy,
|
||||||
ProductWarehouseID: newPWID,
|
ProductWarehouseID: newPWID,
|
||||||
ClearProductWarehouse: clearPW,
|
ClearProductWarehouse: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
if prep.overrideWarehouse || uint(item.WarehouseId) != prep.warehouseID {
|
if prep.overrideWarehouse || uint(item.WarehouseId) != prep.warehouseID {
|
||||||
@@ -972,6 +986,38 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
|||||||
return updated, nil
|
return updated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *purchaseService) uploadTravelDocument(
|
||||||
|
ctx context.Context,
|
||||||
|
actorID uint,
|
||||||
|
itemID uint,
|
||||||
|
file *multipart.FileHeader,
|
||||||
|
) (string, error) {
|
||||||
|
if file == nil {
|
||||||
|
return "", errors.New("travel document file is required")
|
||||||
|
}
|
||||||
|
if s.DocumentSvc == nil {
|
||||||
|
return "", errors.New("document service not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
documentFiles := []commonSvc.DocumentFile{{
|
||||||
|
File: file,
|
||||||
|
Type: string(utils.DocumentTypePurchaseTravel),
|
||||||
|
}}
|
||||||
|
results, err := s.DocumentSvc.UploadDocuments(ctx, commonSvc.DocumentUploadRequest{
|
||||||
|
DocumentableType: string(utils.DocumentableTypePurchaseItem),
|
||||||
|
DocumentableID: uint64(itemID),
|
||||||
|
CreatedBy: &actorID,
|
||||||
|
Files: documentFiles,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(results) == 0 {
|
||||||
|
return "", errors.New("upload result is empty")
|
||||||
|
}
|
||||||
|
return results[0].URL, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *purchaseService) DeleteItems(c *fiber.Ctx, id uint, req *validation.DeletePurchaseItemsRequest) (*entity.Purchase, error) {
|
func (s *purchaseService) DeleteItems(c *fiber.Ctx, id uint, req *validation.DeletePurchaseItemsRequest) (*entity.Purchase, error) {
|
||||||
if err := s.Validate.Struct(req); err != nil {
|
if err := s.Validate.Struct(req); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
|
import "mime/multipart"
|
||||||
|
|
||||||
type PurchaseItemPayload struct {
|
type PurchaseItemPayload struct {
|
||||||
WarehouseID uint `json:"warehouse_id" validate:"required,gt=0"`
|
WarehouseID uint `json:"warehouse_id" validate:"required,gt=0"`
|
||||||
ProductID uint `json:"product_id" validate:"required,gt=0"`
|
ProductID uint `json:"product_id" validate:"required,gt=0"`
|
||||||
@@ -26,7 +28,7 @@ type StaffPurchaseApprovalItem struct {
|
|||||||
|
|
||||||
type ApproveStaffPurchaseRequest struct {
|
type ApproveStaffPurchaseRequest struct {
|
||||||
Action string `json:"action" validate:"required,oneof=APPROVED REJECTED"`
|
Action string `json:"action" validate:"required,oneof=APPROVED REJECTED"`
|
||||||
Items []StaffPurchaseApprovalItem `json:"items,omitempty" validate:"omitempty,min=1,dive"`
|
Items []StaffPurchaseApprovalItem `json:"items" validate:"omitempty,min=1,dive"`
|
||||||
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
|
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,21 +38,22 @@ type ApproveManagerPurchaseRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ReceivePurchaseItemRequest struct {
|
type ReceivePurchaseItemRequest struct {
|
||||||
PurchaseItemID uint `json:"purchase_item_id" validate:"required,gt=0"`
|
PurchaseItemID uint `form:"purchase_item_id" json:"purchase_item_id" validate:"required,gt=0"`
|
||||||
WarehouseID *uint `json:"warehouse_id" validate:"omitempty,gt=0"`
|
WarehouseID *uint `form:"warehouse_id" json:"warehouse_id" validate:"omitempty,gt=0"`
|
||||||
ReceivedDate string `json:"received_date" validate:"required,datetime=2006-01-02"`
|
ReceivedDate string `form:"received_date" json:"received_date" validate:"required,datetime=2006-01-02"`
|
||||||
ExpeditionVendorID *uint `json:"expedition_vendor_id,omitempty" validate:"omitempty,gt=0"`
|
ExpeditionVendorID *uint `form:"expedition_vendor_id" json:"expedition_vendor_id,omitempty" validate:"omitempty,gt=0"`
|
||||||
TransportPerItem *float64 `json:"transport_per_item,omitempty" validate:"omitempty,gte=0"`
|
TransportPerItem *float64 `form:"transport_per_item" json:"transport_per_item,omitempty" validate:"omitempty,gte=0"`
|
||||||
TravelNumber *string `json:"travel_number" validate:"omitempty,max=100"`
|
TravelNumber *string `form:"travel_number" json:"travel_number" validate:"omitempty,max=100"`
|
||||||
TravelDocumentPath *string `json:"travel_document_path" validate:"omitempty,max=255"`
|
TravelDocumentPath *string `form:"travel_document_path" json:"travel_document_path" validate:"omitempty,max=1024"`
|
||||||
VehicleNumber *string `json:"vehicle_number" validate:"omitempty,max=100"`
|
VehicleNumber *string `form:"vehicle_number" json:"vehicle_number" validate:"omitempty,max=100"`
|
||||||
ReceivedQty *float64 `json:"received_qty" validate:"omitempty,gte=0"`
|
ReceivedQty *float64 `form:"received_qty" json:"received_qty" validate:"omitempty,gte=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReceivePurchaseRequest struct {
|
type ReceivePurchaseRequest struct {
|
||||||
Action string `json:"action" validate:"required,oneof=APPROVED REJECTED"`
|
Action string `form:"action" json:"action" validate:"required,oneof=APPROVED REJECTED"`
|
||||||
Items []ReceivePurchaseItemRequest `json:"items,omitempty" validate:"omitempty,min=1,dive"`
|
Items []ReceivePurchaseItemRequest `form:"items" json:"items" validate:"min=1,dive"`
|
||||||
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
|
TravelDocuments []*multipart.FileHeader `form:"travel_documents" json:"-" validate:"omitempty,dive"`
|
||||||
|
Notes *string `form:"notes" json:"notes,omitempty" validate:"omitempty,max=500"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeletePurchaseItemsRequest struct {
|
type DeletePurchaseItemsRequest struct {
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ func RepportRoutes(v1 fiber.Router, u user.UserService, s repport.RepportService
|
|||||||
route.Get("/expense", m.RequirePermissions(m.P_ReportExpenseGetAll), ctrl.GetExpense)
|
route.Get("/expense", m.RequirePermissions(m.P_ReportExpenseGetAll), ctrl.GetExpense)
|
||||||
route.Get("/marketing", m.RequirePermissions(m.P_ReportDeliveryGetAll), ctrl.GetMarketing)
|
route.Get("/marketing", m.RequirePermissions(m.P_ReportDeliveryGetAll), ctrl.GetMarketing)
|
||||||
route.Get("/purchase-supplier", m.RequirePermissions(m.P_ReportPurchaseSupplierGetAll), ctrl.GetPurchaseSupplier)
|
route.Get("/purchase-supplier", m.RequirePermissions(m.P_ReportPurchaseSupplierGetAll), ctrl.GetPurchaseSupplier)
|
||||||
route.Get("/hpp-per-kandang", ctrl.GetHppPerKandang)
|
route.Get("/hpp-per-kandang", m.RequirePermissions(m.P_ReportHppPerKandangGetAll),ctrl.GetHppPerKandang)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -411,10 +411,12 @@ const (
|
|||||||
DocumentTypeTransfer DocumentType = "STOCK_TRANSFER_DOCUMENT"
|
DocumentTypeTransfer DocumentType = "STOCK_TRANSFER_DOCUMENT"
|
||||||
DocumentTypeExpense DocumentType = "EXPENSE_DOCUMENT"
|
DocumentTypeExpense DocumentType = "EXPENSE_DOCUMENT"
|
||||||
DocumentTypeExpenseRealization DocumentType = "EXPENSE_REALIZATION_DOCUMENT"
|
DocumentTypeExpenseRealization DocumentType = "EXPENSE_REALIZATION_DOCUMENT"
|
||||||
|
DocumentTypePurchaseTravel DocumentType = "PURCHASE_TRAVEL_DOCUMENT"
|
||||||
|
|
||||||
DocumentableTypeTransfer DocumentableType = "STOCK_TRANSFER"
|
DocumentableTypeTransfer DocumentableType = "STOCK_TRANSFER"
|
||||||
DocumentableTypeExpense DocumentableType = "EXPENSE"
|
DocumentableTypeExpense DocumentableType = "EXPENSE"
|
||||||
DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION"
|
DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION"
|
||||||
|
DocumentableTypePurchaseItem DocumentableType = "PURCHASE_ITEM"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user