mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat[BE]: enhance expense management with location and project flock integration, including updates to migrations, entities, services, and validations
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
-- Rollback: Update expense and expense_nonstocks tables
|
||||
|
||||
-- Drop indexes
|
||||
DROP INDEX IF EXISTS idx_expenses_project_flock_id;
|
||||
DROP INDEX IF EXISTS idx_expenses_location_id;
|
||||
|
||||
-- Drop Foreign Key constraint
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM pg_constraint
|
||||
WHERE conname = 'fk_expenses_location_id'
|
||||
) THEN
|
||||
ALTER TABLE expenses
|
||||
DROP CONSTRAINT fk_expenses_location_id;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Drop columns from expenses table
|
||||
ALTER TABLE expenses
|
||||
DROP COLUMN IF EXISTS project_flock_id;
|
||||
|
||||
ALTER TABLE expenses
|
||||
DROP COLUMN IF EXISTS location_id;
|
||||
@@ -0,0 +1,29 @@
|
||||
-- Migration: Update expense and expense_nonstocks tables
|
||||
|
||||
-- Add location_id column to expenses table
|
||||
ALTER TABLE expenses
|
||||
ADD COLUMN IF NOT EXISTS location_id BIGINT NOT NULL DEFAULT 1;
|
||||
|
||||
-- Add project_flock_id column to expenses table (JSON type)
|
||||
ALTER TABLE expenses
|
||||
ADD COLUMN IF NOT EXISTS project_flock_id JSON NULL;
|
||||
|
||||
-- Add Foreign Key constraint to locations table
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'locations') THEN
|
||||
ALTER TABLE expenses
|
||||
ADD CONSTRAINT fk_expenses_location_id
|
||||
FOREIGN KEY (location_id) REFERENCES locations(id) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Create index for location_id
|
||||
CREATE INDEX IF NOT EXISTS idx_expenses_location_id ON expenses (location_id);
|
||||
|
||||
-- Create index for project_flock_id
|
||||
CREATE INDEX IF NOT EXISTS idx_expenses_project_flock_id ON expenses ((project_flock_id::text));
|
||||
|
||||
-- Ensure kandang_id is nullable in expense_nonstocks table
|
||||
ALTER TABLE expense_nonstocks
|
||||
ALTER COLUMN kandang_id DROP NOT NULL;
|
||||
@@ -12,6 +12,8 @@ type Expense struct {
|
||||
SupplierId uint64 `gorm:""`
|
||||
Category string `gorm:"type:varchar(50);not null"`
|
||||
PoNumber string `gorm:"type:varchar(50)"`
|
||||
LocationId uint64 `gorm:"not null"`
|
||||
ProjectFlockId *string `gorm:"type:json"`
|
||||
RealizationDate time.Time `gorm:"type:date;column:realization_date"`
|
||||
TransactionDate time.Time `gorm:"type:date;not null"`
|
||||
Notes string `gorm:"type:text;column:notes"`
|
||||
@@ -21,6 +23,7 @@ type Expense struct {
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
Supplier *Supplier `gorm:"foreignKey:SupplierId;references:Id"`
|
||||
Location *Location `gorm:"foreignKey:LocationId;references:Id"`
|
||||
CreatedUser *User `gorm:"foreignKey:CreatedBy;references:Id"`
|
||||
Nonstocks []ExpenseNonstock `gorm:"foreignKey:ExpenseId;references:Id"`
|
||||
Documents []Document `gorm:"foreignKey:DocumentableId;references:Id"`
|
||||
|
||||
@@ -90,6 +90,12 @@ func (u *ExpenseController) CreateOne(c *fiber.Ctx) error {
|
||||
}
|
||||
req.SupplierID = supplierID
|
||||
|
||||
locationID, err := strconv.ParseUint(c.FormValue("location_id"), 10, 64)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid location_id format")
|
||||
}
|
||||
req.LocationID = locationID
|
||||
|
||||
form, err := c.MultipartForm()
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form")
|
||||
@@ -106,17 +112,7 @@ func (u *ExpenseController) CreateOne(c *fiber.Ctx) error {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid expense_nonstocks JSON: %v", err))
|
||||
}
|
||||
|
||||
if singleExpenseNonstock.KandangID == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Field KandangID is required")
|
||||
}
|
||||
|
||||
req.ExpenseNonstocks = []validation.ExpenseNonstock{singleExpenseNonstock}
|
||||
} else {
|
||||
for i, expenseNonstock := range req.ExpenseNonstocks {
|
||||
if expenseNonstock.KandangID == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Field KandangID is required for expense_nonstocks[%d]", i))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Field expense_nonstocks is required")
|
||||
@@ -171,6 +167,15 @@ func (u *ExpenseController) UpdateOne(c *fiber.Ctx) error {
|
||||
req.SupplierID = &supplierID
|
||||
}
|
||||
|
||||
locationIDVal := c.FormValue("location_id")
|
||||
if locationIDVal != "" {
|
||||
locationID, err := strconv.ParseUint(locationIDVal, 10, 64)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid location_id format")
|
||||
}
|
||||
req.LocationID = &locationID
|
||||
}
|
||||
|
||||
expenseNonstocksJSON := c.FormValue("expense_nonstocks")
|
||||
if expenseNonstocksJSON != "" {
|
||||
var expenseNonstocks []validation.ExpenseNonstock
|
||||
@@ -178,12 +183,6 @@ func (u *ExpenseController) UpdateOne(c *fiber.Ctx) error {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid expense_nonstocks JSON: %v", err))
|
||||
}
|
||||
|
||||
for i, expenseNonstock := range expenseNonstocks {
|
||||
if expenseNonstock.KandangID == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Field KandangID is required for expense_nonstocks[%d]", i))
|
||||
}
|
||||
}
|
||||
|
||||
req.ExpenseNonstocks = &expenseNonstocks
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ type ExpenseRealizationDTO struct {
|
||||
|
||||
type KandangGroupDTO struct {
|
||||
Id uint64 `json:"id"`
|
||||
KandangId uint64 `json:"kandang_id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Pengajuans []ExpenseNonstockDTO `json:"pengajuans,omitempty"`
|
||||
Realisasi []ExpenseRealizationDTO `json:"realisasi,omitempty"`
|
||||
@@ -178,7 +177,6 @@ func ToExpenseDetailDTO(e *entity.Expense) ExpenseDetailDTO {
|
||||
var pengajuans []ExpenseNonstockDTO
|
||||
var realisasi []ExpenseRealizationDTO
|
||||
|
||||
// Map documents from Document service
|
||||
for _, doc := range e.Documents {
|
||||
documents = append(documents, DocumentDTO{
|
||||
ID: uint64(doc.Id),
|
||||
@@ -186,7 +184,6 @@ func ToExpenseDetailDTO(e *entity.Expense) ExpenseDetailDTO {
|
||||
})
|
||||
}
|
||||
|
||||
// Map realization documents from Document service
|
||||
for _, doc := range e.RealizationDocuments {
|
||||
realizationDocs = append(realizationDocs, DocumentDTO{
|
||||
ID: uint64(doc.Id),
|
||||
@@ -271,6 +268,8 @@ func ToExpenseNonstockDTO(ns entity.ExpenseNonstock) ExpenseNonstockDTO {
|
||||
|
||||
func ToKandangGroupDTO(pengajuans []ExpenseNonstockDTO, realisasi []ExpenseRealizationDTO, nonstocks []entity.ExpenseNonstock) []KandangGroupDTO {
|
||||
kandangMap := make(map[uint64]*KandangGroupDTO)
|
||||
var directPengajuans []ExpenseNonstockDTO
|
||||
var directRealisasi []ExpenseRealizationDTO
|
||||
|
||||
for _, p := range pengajuans {
|
||||
var kandangId uint64
|
||||
@@ -287,16 +286,19 @@ func ToKandangGroupDTO(pengajuans []ExpenseNonstockDTO, realisasi []ExpenseReali
|
||||
}
|
||||
|
||||
if kandangId > 0 {
|
||||
|
||||
if kandangMap[kandangId] == nil {
|
||||
kandangMap[kandangId] = &KandangGroupDTO{
|
||||
Id: kandangId,
|
||||
KandangId: kandangId,
|
||||
Name: kandangName,
|
||||
Pengajuans: []ExpenseNonstockDTO{},
|
||||
Realisasi: []ExpenseRealizationDTO{},
|
||||
}
|
||||
}
|
||||
kandangMap[kandangId].Pengajuans = append(kandangMap[kandangId].Pengajuans, p)
|
||||
} else {
|
||||
|
||||
directPengajuans = append(directPengajuans, p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,13 +318,24 @@ func ToKandangGroupDTO(pengajuans []ExpenseNonstockDTO, realisasi []ExpenseReali
|
||||
if kandangMap[kandangId] == nil {
|
||||
kandangMap[kandangId] = &KandangGroupDTO{
|
||||
Id: kandangId,
|
||||
KandangId: kandangId,
|
||||
Name: kandangName,
|
||||
Pengajuans: []ExpenseNonstockDTO{},
|
||||
Realisasi: []ExpenseRealizationDTO{},
|
||||
}
|
||||
}
|
||||
kandangMap[kandangId].Realisasi = append(kandangMap[kandangId].Realisasi, r)
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
// If there are direct expenses (without kandang), add them as a special entry with id=0
|
||||
if len(directPengajuans) > 0 || len(directRealisasi) > 0 {
|
||||
kandangMap[0] = &KandangGroupDTO{
|
||||
Id: 0,
|
||||
|
||||
Name: "",
|
||||
Pengajuans: directPengajuans,
|
||||
Realisasi: directRealisasi,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -144,11 +145,8 @@ func (s *expenseService) CreateOne(c *fiber.Ctx, req *validation.Create) (*expen
|
||||
|
||||
supplierID := uint(req.SupplierID)
|
||||
|
||||
supplierExistsFunc := func(ctx context.Context, id uint) (bool, error) {
|
||||
return commonRepo.Exists[entity.Supplier](ctx, s.SupplierRepo.DB(), id)
|
||||
}
|
||||
if err := commonSvc.EnsureRelations(c.Context(),
|
||||
commonSvc.RelationCheck{Name: "Supplier", ID: &supplierID, Exists: supplierExistsFunc},
|
||||
commonSvc.RelationCheck{Name: "Supplier", ID: &supplierID, Exists: s.SupplierRepo.IdExists},
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -199,11 +197,47 @@ func (s *expenseService) CreateOne(c *fiber.Ctx, req *validation.Create) (*expen
|
||||
return fiber.NewError(fiber.StatusUnauthorized, "Failed to get actor ID from context")
|
||||
}
|
||||
createdBy := uint64(actorID)
|
||||
|
||||
hasKandang := false
|
||||
for _, ens := range req.ExpenseNonstocks {
|
||||
if ens.KandangID != nil {
|
||||
hasKandang = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var projectFlockIdJSON *string
|
||||
if !hasKandang && req.Category == string(utils.ExpenseCategoryBOP) {
|
||||
projectFlockRepoTx := projectFlockKandangRepo.NewProjectflockRepository(dbTransaction)
|
||||
activeProjectFlocks, err := projectFlockRepoTx.GetActiveByLocationID(c.Context(), req.LocationID)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get active project flocks for location")
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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{
|
||||
ReferenceNumber: referenceNumber,
|
||||
PoNumber: req.PoNumber,
|
||||
Category: req.Category,
|
||||
SupplierId: req.SupplierID,
|
||||
LocationId: req.LocationID,
|
||||
ProjectFlockId: projectFlockIdJSON,
|
||||
TransactionDate: expenseDate,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
@@ -216,11 +250,17 @@ func (s *expenseService) CreateOne(c *fiber.Ctx, req *validation.Create) (*expen
|
||||
|
||||
for _, expenseNonstock := range req.ExpenseNonstocks {
|
||||
|
||||
isAttachingToKandang := (expenseNonstock.KandangID != nil)
|
||||
|
||||
var projectFlockKandangId *uint64
|
||||
var kandangId *uint64
|
||||
|
||||
if isAttachingToKandang {
|
||||
kandangId = expenseNonstock.KandangID
|
||||
|
||||
if req.Category == string(utils.ExpenseCategoryBOP) {
|
||||
|
||||
projectFlockKandang, err := projectFlockKandangRepoTx.GetActiveByKandangID(c.Context(), uint(expenseNonstock.KandangID))
|
||||
projectFlockKandang, err := projectFlockKandangRepoTx.GetActiveByKandangID(c.Context(), uint(*kandangId))
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, "No active project flock kandang found for this kandang")
|
||||
@@ -231,20 +271,15 @@ func (s *expenseService) CreateOne(c *fiber.Ctx, req *validation.Create) (*expen
|
||||
projectFlockKandangId = &id
|
||||
}
|
||||
|
||||
} else {
|
||||
kandangId = nil
|
||||
projectFlockKandangId = nil
|
||||
}
|
||||
|
||||
for _, costItem := range expenseNonstock.CostItems {
|
||||
|
||||
nonstockId := costItem.NonstockID
|
||||
var kandangId *uint64
|
||||
if req.Category == string(utils.ExpenseCategoryNonBOP) {
|
||||
id := uint64(expenseNonstock.KandangID)
|
||||
kandangId = &id
|
||||
} else if req.Category == string(utils.ExpenseCategoryBOP) {
|
||||
if projectFlockKandangId != nil {
|
||||
kandangId = &expenseNonstock.KandangID
|
||||
}
|
||||
}
|
||||
|
||||
expenseNonstock := &entity.ExpenseNonstock{
|
||||
newExpenseNonstock := &entity.ExpenseNonstock{
|
||||
ExpenseId: &expense.Id,
|
||||
ProjectFlockKandangId: projectFlockKandangId,
|
||||
KandangId: kandangId,
|
||||
@@ -254,7 +289,7 @@ func (s *expenseService) CreateOne(c *fiber.Ctx, req *validation.Create) (*expen
|
||||
Notes: costItem.Notes,
|
||||
}
|
||||
|
||||
if err := expenseNonstockRepoTx.CreateOne(c.Context(), expenseNonstock, nil); err != nil {
|
||||
if err := expenseNonstockRepoTx.CreateOne(c.Context(), newExpenseNonstock, nil); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create expense cost item")
|
||||
}
|
||||
}
|
||||
@@ -361,6 +396,11 @@ func (s expenseService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
updateBody["supplier_id"] = *req.SupplierID
|
||||
}
|
||||
|
||||
if req.LocationID != nil {
|
||||
locationID := uint(*req.LocationID)
|
||||
updateBody["location_id"] = locationID
|
||||
}
|
||||
|
||||
if len(updateBody) == 0 && req.ExpenseNonstocks == nil && len(req.Documents) == 0 {
|
||||
|
||||
responseDTO, err := s.GetOne(c, id)
|
||||
@@ -475,10 +515,16 @@ func (s expenseService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
|
||||
for _, expenseNonstock := range *req.ExpenseNonstocks {
|
||||
var projectFlockKandangId *uint64
|
||||
var kandangId *uint64
|
||||
|
||||
// Check if attaching to kandang
|
||||
if expenseNonstock.KandangID != nil {
|
||||
kandangId = expenseNonstock.KandangID
|
||||
|
||||
if updatedExpense.Category == string(utils.ExpenseCategoryBOP) {
|
||||
// BOP with kandang: Get active project flock kandang
|
||||
projectFlockKandangRepoTx := projectFlockKandangRepo.NewProjectFlockKandangRepository(tx)
|
||||
projectFlockKandang, err := projectFlockKandangRepoTx.GetActiveByKandangID(c.Context(), uint(expenseNonstock.KandangID))
|
||||
projectFlockKandang, err := projectFlockKandangRepoTx.GetActiveByKandangID(c.Context(), uint(*kandangId))
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, "No active project flock kandang found for this kandang")
|
||||
@@ -488,6 +534,8 @@ func (s expenseService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
id := uint64(projectFlockKandang.Id)
|
||||
projectFlockKandangId = &id
|
||||
}
|
||||
// NON-BOP: projectFlockKandangId stays nil
|
||||
}
|
||||
|
||||
for _, costItem := range expenseNonstock.CostItems {
|
||||
|
||||
@@ -498,18 +546,8 @@ func (s expenseService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
return err
|
||||
}
|
||||
|
||||
var kandangId *uint64
|
||||
if updatedExpense.Category == string(utils.ExpenseCategoryNonBOP) {
|
||||
id := uint64(expenseNonstock.KandangID)
|
||||
kandangId = &id
|
||||
} else if updatedExpense.Category == string(utils.ExpenseCategoryBOP) {
|
||||
if projectFlockKandangId != nil {
|
||||
kandangId = &expenseNonstock.KandangID
|
||||
}
|
||||
}
|
||||
|
||||
expenseId := uint64(id)
|
||||
expenseNonstock := &entity.ExpenseNonstock{
|
||||
newExpenseNonstock := &entity.ExpenseNonstock{
|
||||
ExpenseId: &expenseId,
|
||||
ProjectFlockKandangId: projectFlockKandangId,
|
||||
KandangId: kandangId,
|
||||
@@ -519,7 +557,7 @@ func (s expenseService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
Notes: costItem.Notes,
|
||||
}
|
||||
|
||||
if err := expenseNonstockRepoTx.CreateOne(c.Context(), expenseNonstock, nil); err != nil {
|
||||
if err := expenseNonstockRepoTx.CreateOne(c.Context(), newExpenseNonstock, nil); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create expense cost item")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,13 @@ type Create struct {
|
||||
TransactionDate string `form:"transaction_date" json:"transaction_date" validate:"required,datetime=2006-01-02"`
|
||||
Category string `form:"category" json:"category" validate:"required,oneof=BOP NON-BOP"`
|
||||
SupplierID uint64 `form:"supplier_id" json:"supplier_id" validate:"required,gt=0"`
|
||||
LocationID uint64 `form:"location_id" json:"location_id" validate:"required,gt=0"`
|
||||
Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"`
|
||||
ExpenseNonstocks []ExpenseNonstock `form:"expense_nonstocks" json:"expense_nonstocks" validate:"required,min=1,dive"`
|
||||
}
|
||||
|
||||
type ExpenseNonstock struct {
|
||||
KandangID uint64 `form:"kandang_id" json:"kandang_id" validate:"required,gt=0"`
|
||||
KandangID *uint64 `form:"kandang_id" json:"kandang_id" validate:"omitempty"`
|
||||
CostItems []CostItem `form:"cost_items" json:"cost_items" validate:"required,min=1,dive"`
|
||||
}
|
||||
|
||||
@@ -22,13 +23,14 @@ type CostItem struct {
|
||||
NonstockID uint64 `form:"nonstock_id" json:"nonstock_id" validate:"required,gt=0"`
|
||||
Quantity float64 `form:"quantity" json:"quantity" validate:"required,gt=0"`
|
||||
Price float64 `form:"price" json:"price" validate:"required,gt=0"`
|
||||
Notes string `form:"notes" json:"notes" validate:"required,max=500"`
|
||||
Notes string `form:"notes" json:"notes" validate:"omitempty,max=500"`
|
||||
}
|
||||
|
||||
type Update struct {
|
||||
TransactionDate *string `form:"transaction_date" json:"transaction_date" validate:"omitempty,datetime=2006-01-02"`
|
||||
Category *string `form:"category" json:"category" validate:"omitempty,oneof=BOP NON-BOP"`
|
||||
SupplierID *uint64 `form:"supplier_id" json:"supplier_id" validate:"omitempty,gt=0"`
|
||||
LocationID *uint64 `form:"location_id" json:"location_id" validate:"omitempty,gt=0"`
|
||||
Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"`
|
||||
ExpenseNonstocks *[]ExpenseNonstock `form:"expense_nonstocks" json:"expense_nonstocks" validate:"omitempty,min=1,dive"`
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ type SupplierRepository interface {
|
||||
repository.BaseRepository[entity.Supplier]
|
||||
NameExists(ctx context.Context, name string, excludeID *uint) (bool, error)
|
||||
AliasExists(ctx context.Context, alias string, excludeID *uint) (bool, error)
|
||||
IdExists(ctx context.Context, id uint) (bool, error)
|
||||
}
|
||||
|
||||
type SupplierRepositoryImpl struct {
|
||||
@@ -33,3 +34,7 @@ func (r *SupplierRepositoryImpl) NameExists(ctx context.Context, name string, ex
|
||||
func (r *SupplierRepositoryImpl) AliasExists(ctx context.Context, alias string, excludeID *uint) (bool, error) {
|
||||
return repository.ExistsByField[entity.Supplier](ctx, r.db, "alias", alias, excludeID)
|
||||
}
|
||||
|
||||
func (r *SupplierRepositoryImpl) IdExists(ctx context.Context, id uint) (bool, error) {
|
||||
return repository.Exists[entity.Supplier](ctx, r.db, id)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ type ProjectflockRepository interface {
|
||||
GetNextPeriodsForKandangs(ctx context.Context, kandangIDs []uint) (map[uint]int, error)
|
||||
GetCurrentProjectPeriod(ctx context.Context, projectFlockID uint) (int, error)
|
||||
GetKandangPeriodSummaryRows(ctx context.Context, locationID uint) ([]KandangPeriodRow, error)
|
||||
GetActiveByLocationID(ctx context.Context, locationID uint64) ([]entity.ProjectFlock, error)
|
||||
AreaExists(ctx context.Context, id uint) (bool, error)
|
||||
FcrExists(ctx context.Context, id uint) (bool, error)
|
||||
LocationExists(ctx context.Context, id uint) (bool, error)
|
||||
@@ -295,3 +296,17 @@ func (r *ProjectflockRepositoryImpl) ExistsByFlockName(ctx context.Context, floc
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (r *ProjectflockRepositoryImpl) GetActiveByLocationID(ctx context.Context, locationID uint64) ([]entity.ProjectFlock, error) {
|
||||
var projectFlocks []entity.ProjectFlock
|
||||
err := r.DB().WithContext(ctx).
|
||||
Joins("JOIN project_flock_kandangs ON project_flock_kandangs.project_flock_id = project_flocks.id").
|
||||
Where("project_flocks.location_id = ?", locationID).
|
||||
Where("project_flock_kandangs.closed_at IS NULL").
|
||||
Group("project_flocks.id").
|
||||
Find(&projectFlocks).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectFlocks, nil
|
||||
}
|
||||
|
||||
@@ -571,7 +571,7 @@ func (b *expenseBridge) createExpenseViaService(
|
||||
Category: "BOP",
|
||||
SupplierID: uint64(supplierID),
|
||||
ExpenseNonstocks: []expenseValidation.ExpenseNonstock{{
|
||||
KandangID: uint64(*kandangID),
|
||||
KandangID: func() *uint64 { id := uint64(*kandangID); return &id }(),
|
||||
CostItems: costItems,
|
||||
}},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user