mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 15:25:43 +00:00
Merge branch 'development' of https://gitlab.com/mbugroup/lti-api into Feat/BE/Expense_adjust_approval_flow
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
DROP TABLE IF EXISTS expenses;
|
DROP SEQUENCE IF EXISTS expenses_ref_seq;
|
||||||
|
DROP TABLE IF EXISTS expenses;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
-- Drop function and sequence for sales order numbers
|
-- Drop function and sequence for sales order numbers
|
||||||
DROP FUNCTION IF EXISTS generate_so_number();
|
|
||||||
DROP SEQUENCE IF EXISTS so_number_seq;
|
DROP SEQUENCE IF EXISTS so_number_seq;
|
||||||
|
DROP FUNCTION IF EXISTS generate_so_number();
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE payments
|
||||||
|
DROP COLUMN IF EXISTS party_account_number;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE payments
|
||||||
|
ADD COLUMN IF NOT EXISTS party_account_number VARCHAR(50);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE IF EXISTS projects;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE IF EXISTS projects;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-- Revert master data foreign keys to CASCADE delete (except FCR)
|
||||||
|
ALTER TABLE nonstock_suppliers
|
||||||
|
DROP CONSTRAINT IF EXISTS nonstock_suppliers_nonstock_id_fkey,
|
||||||
|
DROP CONSTRAINT IF EXISTS nonstock_suppliers_supplier_id_fkey;
|
||||||
|
|
||||||
|
ALTER TABLE nonstock_suppliers
|
||||||
|
ADD CONSTRAINT nonstock_suppliers_nonstock_id_fkey FOREIGN KEY (nonstock_id)
|
||||||
|
REFERENCES nonstocks (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT nonstock_suppliers_supplier_id_fkey FOREIGN KEY (supplier_id)
|
||||||
|
REFERENCES suppliers (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE product_suppliers
|
||||||
|
DROP CONSTRAINT IF EXISTS product_suppliers_product_id_fkey,
|
||||||
|
DROP CONSTRAINT IF EXISTS product_suppliers_supplier_id_fkey;
|
||||||
|
|
||||||
|
ALTER TABLE product_suppliers
|
||||||
|
ADD CONSTRAINT product_suppliers_product_id_fkey FOREIGN KEY (product_id)
|
||||||
|
REFERENCES products (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT product_suppliers_supplier_id_fkey FOREIGN KEY (supplier_id)
|
||||||
|
REFERENCES suppliers (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-- Update master data foreign keys to RESTRICT delete (except FCR)
|
||||||
|
ALTER TABLE nonstock_suppliers
|
||||||
|
DROP CONSTRAINT IF EXISTS nonstock_suppliers_nonstock_id_fkey,
|
||||||
|
DROP CONSTRAINT IF EXISTS nonstock_suppliers_supplier_id_fkey;
|
||||||
|
|
||||||
|
ALTER TABLE nonstock_suppliers
|
||||||
|
ADD CONSTRAINT nonstock_suppliers_nonstock_id_fkey FOREIGN KEY (nonstock_id)
|
||||||
|
REFERENCES nonstocks (id) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT nonstock_suppliers_supplier_id_fkey FOREIGN KEY (supplier_id)
|
||||||
|
REFERENCES suppliers (id) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE product_suppliers
|
||||||
|
DROP CONSTRAINT IF EXISTS product_suppliers_product_id_fkey,
|
||||||
|
DROP CONSTRAINT IF EXISTS product_suppliers_supplier_id_fkey;
|
||||||
|
|
||||||
|
ALTER TABLE product_suppliers
|
||||||
|
ADD CONSTRAINT product_suppliers_product_id_fkey FOREIGN KEY (product_id)
|
||||||
|
REFERENCES products (id) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT product_suppliers_supplier_id_fkey FOREIGN KEY (supplier_id)
|
||||||
|
REFERENCES suppliers (id) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE recordings
|
||||||
|
DROP CONSTRAINT IF EXISTS chk_recordings_nonnegatives_v4;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'recordings' AND column_name = 'hen_day'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE recordings RENAME COLUMN hen_day TO hand_day;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'recordings' AND column_name = 'hen_house'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE recordings RENAME COLUMN hen_house TO hand_house;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'recordings' AND column_name = 'egg_mass'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE recordings RENAME COLUMN egg_mass TO egg_mesh;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
ALTER TABLE recordings
|
||||||
|
ADD COLUMN IF NOT EXISTS daily_gain NUMERIC(7,3),
|
||||||
|
ADD COLUMN IF NOT EXISTS avg_daily_gain NUMERIC(7,3);
|
||||||
|
|
||||||
|
ALTER TABLE recordings
|
||||||
|
ADD CONSTRAINT chk_recordings_nonnegatives_v3 CHECK (
|
||||||
|
(total_depletion_qty IS NULL OR total_depletion_qty >= 0) AND
|
||||||
|
(cum_depletion_rate IS NULL OR cum_depletion_rate >= 0) AND
|
||||||
|
(daily_gain IS NULL OR daily_gain >= 0) AND
|
||||||
|
(avg_daily_gain IS NULL OR avg_daily_gain >= 0) AND
|
||||||
|
(cum_intake IS NULL OR cum_intake >= 0) AND
|
||||||
|
(fcr_value IS NULL OR fcr_value >= 0) AND
|
||||||
|
(total_chick_qty IS NULL OR total_chick_qty >= 0) AND
|
||||||
|
(hand_day IS NULL OR hand_day >= 0) AND
|
||||||
|
(hand_house IS NULL OR hand_house >= 0) AND
|
||||||
|
(feed_intake IS NULL OR feed_intake >= 0) AND
|
||||||
|
(egg_mesh IS NULL OR egg_mesh >= 0) AND
|
||||||
|
(egg_weight IS NULL OR egg_weight >= 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE recordings
|
||||||
|
DROP CONSTRAINT IF EXISTS chk_recordings_nonnegatives_v3;
|
||||||
|
|
||||||
|
ALTER TABLE recordings
|
||||||
|
DROP COLUMN IF EXISTS daily_gain,
|
||||||
|
DROP COLUMN IF EXISTS avg_daily_gain;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'recordings' AND column_name = 'hand_day'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE recordings RENAME COLUMN hand_day TO hen_day;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'recordings' AND column_name = 'hand_house'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE recordings RENAME COLUMN hand_house TO hen_house;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'recordings' AND column_name = 'egg_mesh'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE recordings RENAME COLUMN egg_mesh TO egg_mass;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
ALTER TABLE recordings
|
||||||
|
ADD CONSTRAINT chk_recordings_nonnegatives_v4 CHECK (
|
||||||
|
(total_depletion_qty IS NULL OR total_depletion_qty >= 0) AND
|
||||||
|
(cum_depletion_rate IS NULL OR cum_depletion_rate >= 0) AND
|
||||||
|
(cum_intake IS NULL OR cum_intake >= 0) AND
|
||||||
|
(fcr_value IS NULL OR fcr_value >= 0) AND
|
||||||
|
(total_chick_qty IS NULL OR total_chick_qty >= 0) AND
|
||||||
|
(hen_day IS NULL OR hen_day >= 0) AND
|
||||||
|
(hen_house IS NULL OR hen_house >= 0) AND
|
||||||
|
(feed_intake IS NULL OR feed_intake >= 0) AND
|
||||||
|
(egg_mass IS NULL OR egg_mass >= 0) AND
|
||||||
|
(egg_weight IS NULL OR egg_weight >= 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -299,6 +299,7 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
|
|||||||
Tax: tax,
|
Tax: tax,
|
||||||
ExpiryPeriod: seed.Expiry,
|
ExpiryPeriod: seed.Expiry,
|
||||||
CreatedBy: createdBy,
|
CreatedBy: createdBy,
|
||||||
|
IsVisible: seed.IsVisible,
|
||||||
}
|
}
|
||||||
if err := tx.Create(&product).Error; err != nil {
|
if err := tx.Create(&product).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -7,22 +7,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Payment struct {
|
type Payment struct {
|
||||||
Id uint `gorm:"primaryKey;autoIncrement"`
|
Id uint `gorm:"primaryKey;autoIncrement"`
|
||||||
PaymentCode string `gorm:"type:varchar(50);not null"`
|
PaymentCode string `gorm:"type:varchar(50);not null"`
|
||||||
ReferenceNumber *string `gorm:"type:varchar(100)"`
|
ReferenceNumber *string `gorm:"type:varchar(100)"`
|
||||||
TransactionType string `gorm:"type:varchar(50)"`
|
TransactionType string `gorm:"type:varchar(50)"`
|
||||||
PartyType string `gorm:"type:varchar(50);not null;index:payments_party_polymorphic,priority:1"`
|
PartyType string `gorm:"type:varchar(50);not null;index:payments_party_polymorphic,priority:1"`
|
||||||
PartyId uint `gorm:"not null;index:payments_party_polymorphic,priority:2"`
|
PartyId uint `gorm:"not null;index:payments_party_polymorphic,priority:2"`
|
||||||
PaymentDate time.Time `gorm:"not null"`
|
PartyAccountNumber *string `gorm:"type:varchar(50)"`
|
||||||
PaymentMethod string `gorm:"type:varchar(20);not null"`
|
PaymentDate time.Time `gorm:"not null"`
|
||||||
BankId *uint `gorm:"not null;index:idx_payments_bank_id"`
|
PaymentMethod string `gorm:"type:varchar(20);not null"`
|
||||||
Direction string `gorm:"type:varchar(5);not null"`
|
BankId *uint `gorm:"not null;index:idx_payments_bank_id"`
|
||||||
Nominal float64 `gorm:"type:numeric(15,3);not null"`
|
Direction string `gorm:"type:varchar(5);not null"`
|
||||||
Notes string `gorm:"type:text;not null"`
|
Nominal float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
Notes string `gorm:"type:text;not null"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
CreatedBy uint `gorm:"index" json:"-"`
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
CreatedBy uint `gorm:"index" json:"-"`
|
||||||
|
|
||||||
BankWarehouse Bank `gorm:"foreignKey:BankId;references:Id"`
|
BankWarehouse Bank `gorm:"foreignKey:BankId;references:Id"`
|
||||||
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type Product struct {
|
|||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
IsVisible bool `gorm:"column:is_visible;default:true"`
|
IsVisible bool ``
|
||||||
|
|
||||||
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
|
||||||
Uom Uom `gorm:"foreignKey:UomId;references:Id"`
|
Uom Uom `gorm:"foreignKey:UomId;references:Id"`
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ type Recording struct {
|
|||||||
CumIntake *int `gorm:"column:cum_intake"`
|
CumIntake *int `gorm:"column:cum_intake"`
|
||||||
FcrValue *float64 `gorm:"column:fcr_value"`
|
FcrValue *float64 `gorm:"column:fcr_value"`
|
||||||
TotalChickQty *float64 `gorm:"column:total_chick_qty"`
|
TotalChickQty *float64 `gorm:"column:total_chick_qty"`
|
||||||
HandDay *float64 `gorm:"column:hand_day"`
|
HenDay *float64 `gorm:"column:hen_day"`
|
||||||
HandHouse *float64 `gorm:"column:hand_house"`
|
HenHouse *float64 `gorm:"column:hen_house"`
|
||||||
FeedIntake *float64 `gorm:"column:feed_intake"`
|
FeedIntake *float64 `gorm:"column:feed_intake"`
|
||||||
EggMesh *float64 `gorm:"column:egg_mesh"`
|
EggMass *float64 `gorm:"column:egg_mass"`
|
||||||
EggWeight *float64 `gorm:"column:egg_weight"`
|
EggWeight *float64 `gorm:"column:egg_weight"`
|
||||||
CreatedBy uint `gorm:"column:created_by"`
|
CreatedBy uint `gorm:"column:created_by"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
@@ -34,11 +34,11 @@ type Recording struct {
|
|||||||
|
|
||||||
LatestApproval *Approval `gorm:"-" json:"-"`
|
LatestApproval *Approval `gorm:"-" json:"-"`
|
||||||
|
|
||||||
StandardHandDay *float64 `gorm:"-"`
|
StandardHenDay *float64 `gorm:"-"`
|
||||||
StandardHandHouse *float64 `gorm:"-"`
|
StandardHenHouse *float64 `gorm:"-"`
|
||||||
StandardFeedIntake *float64 `gorm:"-"`
|
StandardFeedIntake *float64 `gorm:"-"`
|
||||||
StandardMaxDepletion *float64 `gorm:"-"`
|
StandardMaxDepletion *float64 `gorm:"-"`
|
||||||
StandardEggMesh *float64 `gorm:"-"`
|
StandardEggMass *float64 `gorm:"-"`
|
||||||
StandardEggWeight *float64 `gorm:"-"`
|
StandardEggWeight *float64 `gorm:"-"`
|
||||||
StandardFcr *float64 `gorm:"-"`
|
StandardFcr *float64 `gorm:"-"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,20 +101,25 @@ func ToInitialDetailDTO(e entity.Payment) InitialDetailDTO {
|
|||||||
|
|
||||||
func partyFromInitial(e entity.Payment) Party {
|
func partyFromInitial(e entity.Payment) Party {
|
||||||
party := Party{
|
party := Party{
|
||||||
Id: e.PartyId,
|
Id: e.PartyId,
|
||||||
Type: e.PartyType,
|
Type: e.PartyType,
|
||||||
|
}
|
||||||
|
if e.PartyAccountNumber != nil {
|
||||||
|
party.AccountNumber = *e.PartyAccountNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
switch utils.PaymentParty(e.PartyType) {
|
switch utils.PaymentParty(e.PartyType) {
|
||||||
case utils.PaymentPartyCustomer:
|
case utils.PaymentPartyCustomer:
|
||||||
if e.Customer != nil && e.Customer.Id != 0 {
|
if e.Customer != nil && e.Customer.Id != 0 {
|
||||||
party.Name = e.Customer.Name
|
party.Name = e.Customer.Name
|
||||||
party.AccountNumber = e.Customer.AccountNumber
|
if party.AccountNumber == "" {
|
||||||
|
party.AccountNumber = e.Customer.AccountNumber
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case utils.PaymentPartySupplier:
|
case utils.PaymentPartySupplier:
|
||||||
if e.Supplier != nil && e.Supplier.Id != 0 {
|
if e.Supplier != nil && e.Supplier.Id != 0 {
|
||||||
party.Name = e.Supplier.Name
|
party.Name = e.Supplier.Name
|
||||||
if e.Supplier.AccountNumber != nil {
|
if party.AccountNumber == "" && e.Supplier.AccountNumber != nil {
|
||||||
party.AccountNumber = *e.Supplier.AccountNumber
|
party.AccountNumber = *e.Supplier.AccountNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ func (s *initialService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
TransactionType: string(utils.TransactionTypeSaldoAwal),
|
TransactionType: string(utils.TransactionTypeSaldoAwal),
|
||||||
PartyType: party,
|
PartyType: party,
|
||||||
PartyId: req.PartyId,
|
PartyId: req.PartyId,
|
||||||
|
PartyAccountNumber: nil,
|
||||||
PaymentDate: time.Now(),
|
PaymentDate: time.Now(),
|
||||||
PaymentMethod: string(utils.PaymentMethodSaldo),
|
PaymentMethod: string(utils.PaymentMethodSaldo),
|
||||||
BankId: req.BankId,
|
BankId: req.BankId,
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ func (s *injectionService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
|
|||||||
TransactionType: string(utils.TransactionTypeInjection),
|
TransactionType: string(utils.TransactionTypeInjection),
|
||||||
PartyType: string(utils.PaymentPartyCustomer),
|
PartyType: string(utils.PaymentPartyCustomer),
|
||||||
PartyId: 0,
|
PartyId: 0,
|
||||||
|
PartyAccountNumber: nil,
|
||||||
PaymentDate: adjustmentDate,
|
PaymentDate: adjustmentDate,
|
||||||
PaymentMethod: string(utils.PaymentMethodSaldo),
|
PaymentMethod: string(utils.PaymentMethodSaldo),
|
||||||
BankId: req.BankId,
|
BankId: req.BankId,
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
type Create struct {
|
type Create struct {
|
||||||
BankId *uint `json:"bank_id" validate:"required_strict,number,gt=0"`
|
BankId *uint `json:"bank_id" validate:"required_strict,number,gt=0"`
|
||||||
AdjustmentDate string `json:"adjustment_date" validate:"required_strict"`
|
AdjustmentDate string `json:"adjustment_date" validate:"required_strict"`
|
||||||
Nominal float64 `json:"nominal" validate:"required_strict,gt=0"`
|
Nominal float64 `json:"nominal" validate:"required_strict,gt=0"`
|
||||||
Notes string `json:"notes" validate:"required_strict,max=500"`
|
Notes string `json:"notes" validate:"required_strict,max=500"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
BankId *uint `json:"bank_id,omitempty" validate:"omitempty,number,gt=0"`
|
BankId *uint `json:"bank_id,omitempty" validate:"omitempty,number,gt=0"`
|
||||||
AdjustmentDate *string `json:"adjustment_date,omitempty" validate:"omitempty"`
|
AdjustmentDate *string `json:"adjustment_date,omitempty" validate:"omitempty"`
|
||||||
Nominal *float64 `json:"nominal,omitempty" validate:"omitempty,gt=0"`
|
Nominal *float64 `json:"nominal,omitempty" validate:"omitempty,gt=0"`
|
||||||
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
|
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
|
|||||||
@@ -124,20 +124,25 @@ func ToPaymentDetailDTO(e entity.Payment) PaymentDetailDTO {
|
|||||||
|
|
||||||
func partyFromPayment(e entity.Payment) Party {
|
func partyFromPayment(e entity.Payment) Party {
|
||||||
party := Party{
|
party := Party{
|
||||||
Id: e.PartyId,
|
Id: e.PartyId,
|
||||||
Type: e.PartyType,
|
Type: e.PartyType,
|
||||||
|
}
|
||||||
|
if e.PartyAccountNumber != nil {
|
||||||
|
party.AccountNumber = *e.PartyAccountNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
switch utils.PaymentParty(e.PartyType) {
|
switch utils.PaymentParty(e.PartyType) {
|
||||||
case utils.PaymentPartyCustomer:
|
case utils.PaymentPartyCustomer:
|
||||||
if e.Customer != nil && e.Customer.Id != 0 {
|
if e.Customer != nil && e.Customer.Id != 0 {
|
||||||
party.Name = e.Customer.Name
|
party.Name = e.Customer.Name
|
||||||
party.AccountNumber = e.Customer.AccountNumber
|
if party.AccountNumber == "" {
|
||||||
|
party.AccountNumber = e.Customer.AccountNumber
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case utils.PaymentPartySupplier:
|
case utils.PaymentPartySupplier:
|
||||||
if e.Supplier != nil && e.Supplier.Id != 0 {
|
if e.Supplier != nil && e.Supplier.Id != 0 {
|
||||||
party.Name = e.Supplier.Name
|
party.Name = e.Supplier.Name
|
||||||
if e.Supplier.AccountNumber != nil {
|
if party.AccountNumber == "" && e.Supplier.AccountNumber != nil {
|
||||||
party.AccountNumber = *e.Supplier.AccountNumber
|
party.AccountNumber = *e.Supplier.AccountNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func PaymentRoutes(v1 fiber.Router, u user.UserService, s payment.PaymentService
|
|||||||
route := v1.Group("/payments")
|
route := v1.Group("/payments")
|
||||||
route.Use(m.Auth(u))
|
route.Use(m.Auth(u))
|
||||||
|
|
||||||
route.Post("/",m.RequirePermissions(m.P_Finances_Payments_CreateOne), ctrl.CreateOne)
|
route.Post("/", m.RequirePermissions(m.P_Finances_Payments_CreateOne), ctrl.CreateOne)
|
||||||
route.Get("/:id",m.RequirePermissions(m.P_Finances_Payments_GetOne), ctrl.GetOne)
|
route.Get("/:id", m.RequirePermissions(m.P_Finances_Payments_GetOne), ctrl.GetOne)
|
||||||
route.Patch("/:id",m.RequirePermissions(m.P_Finances_Payments_UpdateOne), ctrl.UpdateOne)
|
route.Patch("/:id", m.RequirePermissions(m.P_Finances_Payments_UpdateOne), ctrl.UpdateOne)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,18 +121,19 @@ func (s *paymentService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
}
|
}
|
||||||
|
|
||||||
createBody := &entity.Payment{
|
createBody := &entity.Payment{
|
||||||
PaymentCode: code,
|
PaymentCode: code,
|
||||||
ReferenceNumber: req.ReferenceNumber,
|
ReferenceNumber: req.ReferenceNumber,
|
||||||
TransactionType: transactionType,
|
TransactionType: transactionType,
|
||||||
PartyType: party,
|
PartyType: party,
|
||||||
PartyId: req.PartyId,
|
PartyId: req.PartyId,
|
||||||
PaymentDate: paymentDate,
|
PartyAccountNumber: req.PartyAccountNumber,
|
||||||
PaymentMethod: method,
|
PaymentDate: paymentDate,
|
||||||
BankId: req.BankId,
|
PaymentMethod: method,
|
||||||
Direction: directionForParty(party),
|
BankId: req.BankId,
|
||||||
Nominal: req.Nominal,
|
Direction: directionForParty(party),
|
||||||
Notes: req.Notes,
|
Nominal: req.Nominal,
|
||||||
CreatedBy: actorID,
|
Notes: req.Notes,
|
||||||
|
CreatedBy: actorID,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
||||||
@@ -188,6 +189,9 @@ func (s paymentService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
|||||||
if req.ReferenceNumber != nil {
|
if req.ReferenceNumber != nil {
|
||||||
updateBody["reference_number"] = *req.ReferenceNumber
|
updateBody["reference_number"] = *req.ReferenceNumber
|
||||||
}
|
}
|
||||||
|
if req.PartyAccountNumber != nil {
|
||||||
|
updateBody["party_account_number"] = *req.PartyAccountNumber
|
||||||
|
}
|
||||||
if req.PaymentMethod != nil {
|
if req.PaymentMethod != nil {
|
||||||
method, err := normalizePaymentMethod(*req.PaymentMethod)
|
method, err := normalizePaymentMethod(*req.PaymentMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
type Create struct {
|
type Create struct {
|
||||||
PartyType string `json:"party_type" validate:"required_strict,min=1,max=50"`
|
PartyType string `json:"party_type" validate:"required_strict,min=1,max=50"`
|
||||||
PartyId uint `json:"party_id" validate:"required_strict,number,gt=0"`
|
PartyId uint `json:"party_id" validate:"required_strict,number,gt=0"`
|
||||||
PaymentDate string `json:"payment_date" validate:"required_strict,datetime=2006-01-02"`
|
PartyAccountNumber *string `json:"party_account_number"`
|
||||||
Nominal float64 `json:"nominal" validate:"required_strict"`
|
PaymentDate string `json:"payment_date" validate:"required_strict,datetime=2006-01-02"`
|
||||||
ReferenceNumber *string `json:"reference_number,omitempty"`
|
Nominal float64 `json:"nominal" validate:"required_strict"`
|
||||||
PaymentMethod string `json:"payment_method" validate:"required_strict,max=20"`
|
ReferenceNumber *string `json:"reference_number,omitempty"`
|
||||||
BankId *uint `json:"bank_id" validate:"omitempty,number,gt=0"`
|
PaymentMethod string `json:"payment_method" validate:"required_strict,max=20"`
|
||||||
Notes string `json:"notes" validate:"required_strict,max=500"`
|
BankId *uint `json:"bank_id" validate:"omitempty,number,gt=0"`
|
||||||
|
Notes string `json:"notes" validate:"required_strict,max=500"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
PartyType *string `json:"party_type,omitempty" validate:"omitempty,max=50"`
|
PartyType *string `json:"party_type,omitempty" validate:"omitempty,max=50"`
|
||||||
PartyId *uint `json:"party_id,omitempty" validate:"omitempty,number,gt=0"`
|
PartyId *uint `json:"party_id,omitempty" validate:"omitempty,number,gt=0"`
|
||||||
PaymentDate *string `json:"payment_date,omitempty" validate:"omitempty,datetime=2006-01-02"`
|
PartyAccountNumber *string `json:"party_account_number,omitempty"`
|
||||||
Nominal *float64 `json:"nominal,omitempty" validate:"omitempty,gt=0"`
|
PaymentDate *string `json:"payment_date,omitempty" validate:"omitempty,datetime=2006-01-02"`
|
||||||
ReferenceNumber *string `json:"reference_number,omitempty"`
|
Nominal *float64 `json:"nominal,omitempty" validate:"omitempty,gt=0"`
|
||||||
PaymentMethod *string `json:"payment_method,omitempty" validate:"omitempty,max=20"`
|
ReferenceNumber *string `json:"reference_number,omitempty"`
|
||||||
BankId *uint `json:"bank_id,omitempty" validate:"omitempty,number,gt=0"`
|
PaymentMethod *string `json:"payment_method,omitempty" validate:"omitempty,max=20"`
|
||||||
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
|
BankId *uint `json:"bank_id,omitempty" validate:"omitempty,number,gt=0"`
|
||||||
|
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
|
|||||||
@@ -124,20 +124,25 @@ func ToTransactionDetailDTO(e entity.Payment) TransactionDetailDTO {
|
|||||||
|
|
||||||
func partyFromPayment(e entity.Payment) Party {
|
func partyFromPayment(e entity.Payment) Party {
|
||||||
party := Party{
|
party := Party{
|
||||||
Id: e.PartyId,
|
Id: e.PartyId,
|
||||||
Type: e.PartyType,
|
Type: e.PartyType,
|
||||||
|
}
|
||||||
|
if e.PartyAccountNumber != nil {
|
||||||
|
party.AccountNumber = *e.PartyAccountNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
switch utils.PaymentParty(e.PartyType) {
|
switch utils.PaymentParty(e.PartyType) {
|
||||||
case utils.PaymentPartyCustomer:
|
case utils.PaymentPartyCustomer:
|
||||||
if e.Customer != nil && e.Customer.Id != 0 {
|
if e.Customer != nil && e.Customer.Id != 0 {
|
||||||
party.Name = e.Customer.Name
|
party.Name = e.Customer.Name
|
||||||
party.AccountNumber = e.Customer.AccountNumber
|
if party.AccountNumber == "" {
|
||||||
|
party.AccountNumber = e.Customer.AccountNumber
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case utils.PaymentPartySupplier:
|
case utils.PaymentPartySupplier:
|
||||||
if e.Supplier != nil && e.Supplier.Id != 0 {
|
if e.Supplier != nil && e.Supplier.Id != 0 {
|
||||||
party.Name = e.Supplier.Name
|
party.Name = e.Supplier.Name
|
||||||
if e.Supplier.AccountNumber != nil {
|
if party.AccountNumber == "" && e.Supplier.AccountNumber != nil {
|
||||||
party.AccountNumber = *e.Supplier.AccountNumber
|
party.AccountNumber = *e.Supplier.AccountNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
@@ -23,6 +23,7 @@ type ProductWarehouseRepository interface {
|
|||||||
GetLatestByCategoryCodeAndWarehouseID(ctx context.Context, categoryCode string, warehouseId uint, db *gorm.DB) (*entity.ProductWarehouse, error)
|
GetLatestByCategoryCodeAndWarehouseID(ctx context.Context, categoryCode string, warehouseId uint, db *gorm.DB) (*entity.ProductWarehouse, error)
|
||||||
GetByFlagAndWarehouseID(ctx context.Context, flagName string, warehouseId uint) ([]entity.ProductWarehouse, error)
|
GetByFlagAndWarehouseID(ctx context.Context, flagName string, warehouseId uint) ([]entity.ProductWarehouse, error)
|
||||||
GetFirstProductByFlag(ctx context.Context, flagName string) (*entity.Product, error)
|
GetFirstProductByFlag(ctx context.Context, flagName string) (*entity.Product, error)
|
||||||
|
ListProductIDsByFlagPrefixes(ctx context.Context, prefixes []string, visibleStatus *bool) ([]uint, error)
|
||||||
ApplyFlagsFilter(db *gorm.DB, flags []string) *gorm.DB
|
ApplyFlagsFilter(db *gorm.DB, flags []string) *gorm.DB
|
||||||
AdjustQuantities(ctx context.Context, deltas map[uint]float64, modifier func(*gorm.DB) *gorm.DB) error
|
AdjustQuantities(ctx context.Context, deltas map[uint]float64, modifier func(*gorm.DB) *gorm.DB) error
|
||||||
GetDetailByID(ctx context.Context, id uint) (*entity.ProductWarehouse, error)
|
GetDetailByID(ctx context.Context, id uint) (*entity.ProductWarehouse, error)
|
||||||
@@ -380,3 +381,38 @@ func (r *ProductWarehouseRepositoryImpl) GetFirstProductByFlag(ctx context.Conte
|
|||||||
}
|
}
|
||||||
return &product, nil
|
return &product, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ProductWarehouseRepositoryImpl) ListProductIDsByFlagPrefixes(ctx context.Context, prefixes []string, visibleStatus *bool) ([]uint, error) {
|
||||||
|
if len(prefixes) == 0 {
|
||||||
|
return []uint{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
db := r.DB().WithContext(ctx).
|
||||||
|
Model(&entity.Product{}).
|
||||||
|
Distinct("products.id").
|
||||||
|
Joins("JOIN flags ON flags.flagable_id = products.id AND flags.flagable_type = ?", entity.FlagableTypeProduct)
|
||||||
|
|
||||||
|
applied := false
|
||||||
|
for _, prefix := range prefixes {
|
||||||
|
if prefix == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
like := prefix + "%"
|
||||||
|
if !applied {
|
||||||
|
db = db.Where("flags.name LIKE ?", like)
|
||||||
|
applied = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
db = db.Or("flags.name LIKE ?", like)
|
||||||
|
}
|
||||||
|
|
||||||
|
if visibleStatus != nil {
|
||||||
|
db = db.Where("products.is_visible = ?", *visibleStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ids []uint
|
||||||
|
if err := db.Pluck("products.id", &ids).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto"
|
productCategoryDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto"
|
||||||
|
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"
|
||||||
)
|
)
|
||||||
@@ -19,6 +20,7 @@ type ProductRelationDTO struct {
|
|||||||
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
||||||
Flags *[]string `json:"flags,omitempty"`
|
Flags *[]string `json:"flags,omitempty"`
|
||||||
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
||||||
|
Suppliers []supplierDTO.SupplierRelationDTO `json:"suppliers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductListDTO struct {
|
type ProductListDTO struct {
|
||||||
@@ -33,6 +35,7 @@ type ProductListDTO struct {
|
|||||||
Flags []string `json:"flags"`
|
Flags []string `json:"flags"`
|
||||||
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
||||||
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
ProductCategory *productCategoryDTO.ProductCategoryRelationDTO `json:"product_category,omitempty"`
|
||||||
|
Suppliers []supplierDTO.SupplierRelationDTO `json:"suppliers"`
|
||||||
CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
|
CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
@@ -70,6 +73,7 @@ func ToProductRelationDTO(e entity.Product) ProductRelationDTO {
|
|||||||
Flags: &flags,
|
Flags: &flags,
|
||||||
Uom: uomRef,
|
Uom: uomRef,
|
||||||
ProductCategory: categoryRef,
|
ProductCategory: categoryRef,
|
||||||
|
Suppliers: toProductSupplierDTOs(e.ProductSuppliers),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +116,7 @@ func ToProductListDTO(e entity.Product) ProductListDTO {
|
|||||||
UpdatedAt: e.UpdatedAt,
|
UpdatedAt: e.UpdatedAt,
|
||||||
CreatedUser: createdUser,
|
CreatedUser: createdUser,
|
||||||
ProductCategory: categoryRef,
|
ProductCategory: categoryRef,
|
||||||
|
Suppliers: toProductSupplierDTOs(e.ProductSuppliers),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,3 +133,23 @@ func ToProductDetailDTO(e entity.Product) ProductDetailDTO {
|
|||||||
ProductListDTO: ToProductListDTO(e),
|
ProductListDTO: ToProductListDTO(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toProductSupplierDTOs(relations []entity.ProductSupplier) []supplierDTO.SupplierRelationDTO {
|
||||||
|
if len(relations) == 0 {
|
||||||
|
return make([]supplierDTO.SupplierRelationDTO, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 make([]supplierDTO.SupplierRelationDTO, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
|
||||||
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||||
uniformityRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories"
|
uniformityRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories"
|
||||||
|
purchaseRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
||||||
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||||
|
|
||||||
@@ -308,12 +309,12 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
createBody := &entity.ProjectFlock{
|
createBody := &entity.ProjectFlock{
|
||||||
AreaId: req.AreaId,
|
AreaId: req.AreaId,
|
||||||
Category: cat,
|
Category: cat,
|
||||||
FcrId: req.FcrId,
|
FcrId: req.FcrId,
|
||||||
ProductionStandardId: req.ProductionStandardId,
|
ProductionStandardId: req.ProductionStandardId,
|
||||||
LocationId: req.LocationId,
|
LocationId: req.LocationId,
|
||||||
CreatedBy: actorID,
|
CreatedBy: actorID,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
||||||
@@ -823,22 +824,7 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction *
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
blocked, err := s.pivotRepoWithTx(dbTransaction).FindKandangsWithRecordings(ctx, projectFlockID, kandangIDs)
|
// NOTE: Recording constraints are enforced via FK cascade; allow detachment even if recordings exist.
|
||||||
if err != nil {
|
|
||||||
s.Log.Errorf("Failed to check recordings before detaching kandangs: %+v", err)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to validate kandang detachment")
|
|
||||||
}
|
|
||||||
if len(blocked) > 0 {
|
|
||||||
names := make([]string, 0, len(blocked))
|
|
||||||
for _, item := range blocked {
|
|
||||||
label := fmt.Sprintf("ID %d", item.Id)
|
|
||||||
if strings.TrimSpace(item.Name) != "" {
|
|
||||||
label = fmt.Sprintf("%s (%s)", label, item.Name)
|
|
||||||
}
|
|
||||||
names = append(names, label)
|
|
||||||
}
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Tidak dapat melepas kandang karena sudah memiliki recording: %s", strings.Join(names, ", ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
pfkIDs, err := s.pivotRepoWithTx(dbTransaction).ListIDsByProjectAndKandang(ctx, projectFlockID, kandangIDs)
|
pfkIDs, err := s.pivotRepoWithTx(dbTransaction).ListIDsByProjectAndKandang(ctx, projectFlockID, kandangIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -854,6 +840,14 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction *
|
|||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove uniformity data for project flock kandang")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove uniformity data for project flock kandang")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db := s.Repository.DB()
|
||||||
|
if dbTransaction != nil {
|
||||||
|
db = dbTransaction
|
||||||
|
}
|
||||||
|
purchaseRepo := purchaseRepository.NewPurchaseRepository(db)
|
||||||
|
if err := purchaseRepo.SoftDeleteByProjectFlockKandangIDs(ctx, pfkIDs); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to soft delete purchases for project flock kandang")
|
||||||
|
}
|
||||||
pwRepo := s.ProductWarehouseRepo
|
pwRepo := s.ProductWarehouseRepo
|
||||||
if dbTransaction != nil {
|
if dbTransaction != nil {
|
||||||
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
|
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
|
||||||
@@ -906,6 +900,11 @@ func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx cont
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
projectFlockID := records[0].ProjectFlockId
|
||||||
|
if projectFlockID == 0 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Project flock id tidak ditemukan")
|
||||||
|
}
|
||||||
|
|
||||||
pwRepo := s.ProductWarehouseRepo
|
pwRepo := s.ProductWarehouseRepo
|
||||||
if dbTransaction != nil {
|
if dbTransaction != nil {
|
||||||
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
|
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
|
||||||
@@ -920,24 +919,34 @@ func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx cont
|
|||||||
warehouseRepo = warehouseRepository.NewWarehouseRepository(s.Repository.DB())
|
warehouseRepo = warehouseRepository.NewWarehouseRepository(s.Repository.DB())
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := []utils.FlagType{
|
db := s.Repository.DB()
|
||||||
utils.FlagAyamAfkir,
|
if dbTransaction != nil {
|
||||||
utils.FlagAyamCulling,
|
db = dbTransaction
|
||||||
utils.FlagAyamMati,
|
}
|
||||||
utils.FlagTelurPecah,
|
var category string
|
||||||
utils.FlagTelurUtuh,
|
if err := db.WithContext(ctx).
|
||||||
|
Model(&entity.ProjectFlock{}).
|
||||||
|
Select("category").
|
||||||
|
Where("id = ?", projectFlockID).
|
||||||
|
Scan(&category).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(category) == "" {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Project flock category tidak ditemukan")
|
||||||
}
|
}
|
||||||
|
|
||||||
productIDs := make(map[utils.FlagType]uint, len(flags))
|
prefixes := []string{"AYAM-"}
|
||||||
for _, flag := range flags {
|
if strings.EqualFold(category, string(utils.ProjectFlockCategoryLaying)) {
|
||||||
product, err := pwRepo.GetFirstProductByFlag(ctx, string(flag))
|
prefixes = append(prefixes, "TELUR")
|
||||||
if err != nil {
|
}
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Product untuk flag %s tidak ditemukan", flag))
|
invisibleOnly := false
|
||||||
}
|
productIDs, err := pwRepo.ListProductIDsByFlagPrefixes(ctx, prefixes, &invisibleOnly)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
productIDs[flag] = product.Id
|
}
|
||||||
|
if len(productIDs) == 0 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Product dengan flag %s tidak ditemukan", strings.Join(prefixes, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, record := range records {
|
for _, record := range records {
|
||||||
@@ -953,8 +962,7 @@ func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx cont
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, flag := range flags {
|
for _, productID := range productIDs {
|
||||||
productID := productIDs[flag]
|
|
||||||
if _, err := pwRepo.GetByProductWarehouseAndProjectFlockKandang(ctx, productID, warehouse.Id, record.Id); err == nil {
|
if _, err := pwRepo.GetByProductWarehouseAndProjectFlockKandang(ctx, productID, warehouse.Id, record.Id); err == nil {
|
||||||
continue
|
continue
|
||||||
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
|||||||
@@ -25,16 +25,16 @@ type RecordingRelationDTO struct {
|
|||||||
CumIntake int `json:"cum_intake"`
|
CumIntake int `json:"cum_intake"`
|
||||||
FcrValue float64 `json:"fcr_value"`
|
FcrValue float64 `json:"fcr_value"`
|
||||||
TotalChickQty float64 `json:"total_chick_qty"`
|
TotalChickQty float64 `json:"total_chick_qty"`
|
||||||
HandDay float64 `json:"hand_day"`
|
HenDay float64 `json:"hen_day"`
|
||||||
HandHouse float64 `json:"hand_house"`
|
HenHouse float64 `json:"hen_house"`
|
||||||
FeedIntake float64 `json:"feed_intake"`
|
FeedIntake float64 `json:"feed_intake"`
|
||||||
EggMesh float64 `json:"egg_mesh"`
|
EggMass float64 `json:"egg_mass"`
|
||||||
EggWeight float64 `json:"egg_weight"`
|
EggWeight float64 `json:"egg_weight"`
|
||||||
StandardHandDay *float64 `json:"hand_day_std,omitempty"`
|
StandardHenDay *float64 `json:"hen_day_std,omitempty"`
|
||||||
StandardHandHouse *float64 `json:"hand_house_std,omitempty"`
|
StandardHenHouse *float64 `json:"hen_house_std,omitempty"`
|
||||||
StandardFeedIntake *float64 `json:"feed_intake_std,omitempty"`
|
StandardFeedIntake *float64 `json:"feed_intake_std,omitempty"`
|
||||||
StandardMaxDepletion *float64 `json:"max_depletion_std,omitempty"`
|
StandardMaxDepletion *float64 `json:"max_depletion_std,omitempty"`
|
||||||
StandardEggMesh *float64 `json:"egg_mesh_std,omitempty"`
|
StandardEggMass *float64 `json:"egg_mass_std,omitempty"`
|
||||||
StandardEggWeight *float64 `json:"egg_weight_std,omitempty"`
|
StandardEggWeight *float64 `json:"egg_weight_std,omitempty"`
|
||||||
StandardFcr *float64 `json:"fcr_std,omitempty"`
|
StandardFcr *float64 `json:"fcr_std,omitempty"`
|
||||||
Approval approvalDTO.ApprovalRelationDTO `json:"approval"`
|
Approval approvalDTO.ApprovalRelationDTO `json:"approval"`
|
||||||
@@ -94,10 +94,10 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO {
|
|||||||
cumIntake int
|
cumIntake int
|
||||||
fcrValue float64
|
fcrValue float64
|
||||||
totalChickQty float64
|
totalChickQty float64
|
||||||
handDay float64
|
henDay float64
|
||||||
handHouse float64
|
henHouse float64
|
||||||
feedIntake float64
|
feedIntake float64
|
||||||
eggMesh float64
|
eggMass float64
|
||||||
eggWeight float64
|
eggWeight float64
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -119,17 +119,17 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO {
|
|||||||
if e.TotalChickQty != nil {
|
if e.TotalChickQty != nil {
|
||||||
totalChickQty = *e.TotalChickQty
|
totalChickQty = *e.TotalChickQty
|
||||||
}
|
}
|
||||||
if e.HandDay != nil {
|
if e.HenDay != nil {
|
||||||
handDay = *e.HandDay
|
henDay = *e.HenDay
|
||||||
}
|
}
|
||||||
if e.HandHouse != nil {
|
if e.HenHouse != nil {
|
||||||
handHouse = *e.HandHouse
|
henHouse = *e.HenHouse
|
||||||
}
|
}
|
||||||
if e.FeedIntake != nil {
|
if e.FeedIntake != nil {
|
||||||
feedIntake = *e.FeedIntake
|
feedIntake = *e.FeedIntake
|
||||||
}
|
}
|
||||||
if e.EggMesh != nil {
|
if e.EggMass != nil {
|
||||||
eggMesh = *e.EggMesh
|
eggMass = *e.EggMass
|
||||||
}
|
}
|
||||||
if e.EggWeight != nil {
|
if e.EggWeight != nil {
|
||||||
eggWeight = *e.EggWeight
|
eggWeight = *e.EggWeight
|
||||||
@@ -157,16 +157,16 @@ func ToRecordingRelationDTO(e entity.Recording) RecordingRelationDTO {
|
|||||||
CumIntake: cumIntake,
|
CumIntake: cumIntake,
|
||||||
FcrValue: fcrValue,
|
FcrValue: fcrValue,
|
||||||
TotalChickQty: totalChickQty,
|
TotalChickQty: totalChickQty,
|
||||||
HandDay: handDay,
|
HenDay: henDay,
|
||||||
HandHouse: handHouse,
|
HenHouse: henHouse,
|
||||||
FeedIntake: feedIntake,
|
FeedIntake: feedIntake,
|
||||||
EggMesh: eggMesh,
|
EggMass: eggMass,
|
||||||
EggWeight: eggWeight,
|
EggWeight: eggWeight,
|
||||||
StandardHandDay: e.StandardHandDay,
|
StandardHenDay: e.StandardHenDay,
|
||||||
StandardHandHouse: e.StandardHandHouse,
|
StandardHenHouse: e.StandardHenHouse,
|
||||||
StandardFeedIntake: e.StandardFeedIntake,
|
StandardFeedIntake: e.StandardFeedIntake,
|
||||||
StandardMaxDepletion: e.StandardMaxDepletion,
|
StandardMaxDepletion: e.StandardMaxDepletion,
|
||||||
StandardEggMesh: e.StandardEggMesh,
|
StandardEggMass: e.StandardEggMass,
|
||||||
StandardEggWeight: e.StandardEggWeight,
|
StandardEggWeight: e.StandardEggWeight,
|
||||||
StandardFcr: e.StandardFcr,
|
StandardFcr: e.StandardFcr,
|
||||||
Approval: latestApproval,
|
Approval: latestApproval,
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ func RecordingRoutes(v1 fiber.Router, u user.UserService, s recording.RecordingS
|
|||||||
route.Use(m.Auth(u))
|
route.Use(m.Auth(u))
|
||||||
|
|
||||||
route.Get("/",m.RequirePermissions(m.P_RecordingGetAll), ctrl.GetAll)
|
route.Get("/",m.RequirePermissions(m.P_RecordingGetAll), ctrl.GetAll)
|
||||||
|
route.Get("/next-day",m.RequirePermissions(m.P_RecordingNextDay), ctrl.GetNextDay)
|
||||||
route.Get("/:id",m.RequirePermissions(m.P_RecordingGetOne), ctrl.GetOne)
|
route.Get("/:id",m.RequirePermissions(m.P_RecordingGetOne), ctrl.GetOne)
|
||||||
route.Post("/",m.RequirePermissions(m.P_RecordingCreateOne), ctrl.CreateOne)
|
route.Post("/",m.RequirePermissions(m.P_RecordingCreateOne), ctrl.CreateOne)
|
||||||
route.Patch("/:id",m.RequirePermissions(m.P_RecordingUpdateOne), ctrl.UpdateOne)
|
route.Patch("/:id",m.RequirePermissions(m.P_RecordingUpdateOne), ctrl.UpdateOne)
|
||||||
route.Delete("/:id",m.RequirePermissions(m.P_RecordingDeleteOne), ctrl.DeleteOne)
|
route.Delete("/:id",m.RequirePermissions(m.P_RecordingDeleteOne), ctrl.DeleteOne)
|
||||||
route.Get("/next-day",m.RequirePermissions(m.P_RecordingNextDay), ctrl.GetNextDay)
|
|
||||||
route.Post("/approvals",m.RequirePermissions(m.P_RecordingApproval), ctrl.Approve)
|
route.Post("/approvals",m.RequirePermissions(m.P_RecordingApproval), ctrl.Approve)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -901,47 +901,6 @@ type eggTotals struct {
|
|||||||
Weight float64
|
Weight float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type stockTotals struct {
|
|
||||||
Usage float64
|
|
||||||
Pending float64
|
|
||||||
Total float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func summarizeExistingStocks(stocks []entity.RecordingStock) map[uint]stockTotals {
|
|
||||||
totals := make(map[uint]stockTotals)
|
|
||||||
for _, stock := range stocks {
|
|
||||||
var usage float64
|
|
||||||
var pending float64
|
|
||||||
if stock.UsageQty != nil {
|
|
||||||
usage = *stock.UsageQty
|
|
||||||
}
|
|
||||||
if stock.PendingQty != nil {
|
|
||||||
pending = *stock.PendingQty
|
|
||||||
}
|
|
||||||
current := totals[stock.ProductWarehouseId]
|
|
||||||
current.Usage += usage
|
|
||||||
current.Pending += pending
|
|
||||||
current.Total += usage + pending
|
|
||||||
totals[stock.ProductWarehouseId] = current
|
|
||||||
}
|
|
||||||
return totals
|
|
||||||
}
|
|
||||||
|
|
||||||
func summarizeIncomingStocks(stocks []validation.Stock) map[uint]stockTotals {
|
|
||||||
totals := make(map[uint]stockTotals)
|
|
||||||
for _, stock := range stocks {
|
|
||||||
var pending float64
|
|
||||||
if stock.PendingQty != nil {
|
|
||||||
pending = *stock.PendingQty
|
|
||||||
}
|
|
||||||
current := totals[stock.ProductWarehouseId]
|
|
||||||
current.Usage += stock.Qty
|
|
||||||
current.Pending += pending
|
|
||||||
current.Total += stock.Qty + pending
|
|
||||||
totals[stock.ProductWarehouseId] = current
|
|
||||||
}
|
|
||||||
return totals
|
|
||||||
}
|
|
||||||
|
|
||||||
func stocksMatch(existing []entity.RecordingStock, incoming []validation.Stock) bool {
|
func stocksMatch(existing []entity.RecordingStock, incoming []validation.Stock) bool {
|
||||||
hasPending := false
|
hasPending := false
|
||||||
@@ -1156,34 +1115,34 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm
|
|||||||
recording.FeedIntake = nil
|
recording.FeedIntake = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var handDay float64
|
var henDay float64
|
||||||
if remainingChick > 0 && totalEggQty >= 0 {
|
if remainingChick > 0 && totalEggQty >= 0 {
|
||||||
handDay = (totalEggQty / remainingChick) * 100
|
henDay = (totalEggQty / remainingChick) * 100
|
||||||
updates["hand_day"] = handDay
|
updates["hen_day"] = henDay
|
||||||
recording.HandDay = &handDay
|
recording.HenDay = &henDay
|
||||||
} else {
|
} else {
|
||||||
updates["hand_day"] = gorm.Expr("NULL")
|
updates["hen_day"] = gorm.Expr("NULL")
|
||||||
recording.HandDay = nil
|
recording.HenDay = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var handHouse float64
|
var henHouse float64
|
||||||
if initialChickin > 0 && cumulativeEggQty >= 0 {
|
if initialChickin > 0 && cumulativeEggQty >= 0 {
|
||||||
handHouse = cumulativeEggQty / initialChickin
|
henHouse = cumulativeEggQty / initialChickin
|
||||||
updates["hand_house"] = handHouse
|
updates["hen_house"] = henHouse
|
||||||
recording.HandHouse = &handHouse
|
recording.HenHouse = &henHouse
|
||||||
} else {
|
} else {
|
||||||
updates["hand_house"] = gorm.Expr("NULL")
|
updates["hen_house"] = gorm.Expr("NULL")
|
||||||
recording.HandHouse = nil
|
recording.HenHouse = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var eggMesh float64
|
var eggMass float64
|
||||||
if remainingChick > 0 && totalEggWeightGrams > 0 {
|
if remainingChick > 0 && totalEggWeightGrams > 0 {
|
||||||
eggMesh = (totalEggWeightGrams / remainingChick) * 1000
|
eggMass = (totalEggWeightGrams / remainingChick) * 1000
|
||||||
updates["egg_mesh"] = eggMesh
|
updates["egg_mass"] = eggMass
|
||||||
recording.EggMesh = &eggMesh
|
recording.EggMass = &eggMass
|
||||||
} else {
|
} else {
|
||||||
updates["egg_mesh"] = gorm.Expr("NULL")
|
updates["egg_mass"] = gorm.Expr("NULL")
|
||||||
recording.EggMesh = nil
|
recording.EggMass = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var eggWeight float64
|
var eggWeight float64
|
||||||
@@ -1334,11 +1293,11 @@ func (s *recordingService) attachLatestApproval(ctx context.Context, item *entit
|
|||||||
}
|
}
|
||||||
|
|
||||||
type productionStandardValues struct {
|
type productionStandardValues struct {
|
||||||
HandDay *float64
|
HenDay *float64
|
||||||
HandHouse *float64
|
HenHouse *float64
|
||||||
FeedIntake *float64
|
FeedIntake *float64
|
||||||
MaxDepletion *float64
|
MaxDepletion *float64
|
||||||
EggMesh *float64
|
EggMass *float64
|
||||||
EggWeight *float64
|
EggWeight *float64
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1389,10 +1348,10 @@ func (s *recordingService) attachProductionStandard(ctx context.Context, item *e
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if detail != nil {
|
if detail != nil {
|
||||||
standard.HandDay = detail.TargetHenDayProduction
|
standard.HenDay = detail.TargetHenDayProduction
|
||||||
standard.HandHouse = detail.TargetHenHouseProduction
|
standard.HenHouse = detail.TargetHenHouseProduction
|
||||||
standard.EggWeight = detail.TargetEggWeight
|
standard.EggWeight = detail.TargetEggWeight
|
||||||
standard.EggMesh = detail.TargetEggMass
|
standard.EggMass = detail.TargetEggMass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1420,11 +1379,11 @@ func (s *recordingService) attachProductionStandard(ctx context.Context, item *e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item.StandardHandDay = standard.HandDay
|
item.StandardHenDay = standard.HenDay
|
||||||
item.StandardHandHouse = standard.HandHouse
|
item.StandardHenHouse = standard.HenHouse
|
||||||
item.StandardFeedIntake = standard.FeedIntake
|
item.StandardFeedIntake = standard.FeedIntake
|
||||||
item.StandardMaxDepletion = standard.MaxDepletion
|
item.StandardMaxDepletion = standard.MaxDepletion
|
||||||
item.StandardEggMesh = standard.EggMesh
|
item.StandardEggMass = standard.EggMass
|
||||||
item.StandardEggWeight = standard.EggWeight
|
item.StandardEggWeight = standard.EggWeight
|
||||||
item.StandardFcr = standardFcr
|
item.StandardFcr = standardFcr
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type PurchaseRepository interface {
|
|||||||
NextPrNumber(ctx context.Context, tx *gorm.DB) (string, error)
|
NextPrNumber(ctx context.Context, tx *gorm.DB) (string, error)
|
||||||
NextPoNumber(ctx context.Context, tx *gorm.DB) (string, error)
|
NextPoNumber(ctx context.Context, tx *gorm.DB) (string, error)
|
||||||
BackfillProjectFlockKandang(ctx context.Context, purchaseID uint) error
|
BackfillProjectFlockKandang(ctx context.Context, purchaseID uint) error
|
||||||
|
SoftDeleteByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) error
|
||||||
GetItemsByProjectFlockID(ctx context.Context, projectFlockID uint) ([]entity.PurchaseItem, error)
|
GetItemsByProjectFlockID(ctx context.Context, projectFlockID uint) ([]entity.PurchaseItem, error)
|
||||||
GetItemsByWarehouseKandang(ctx context.Context, projectFlockID uint) ([]entity.PurchaseItem, error)
|
GetItemsByWarehouseKandang(ctx context.Context, projectFlockID uint) ([]entity.PurchaseItem, error)
|
||||||
}
|
}
|
||||||
@@ -89,6 +90,44 @@ WHERE pi.purchase_id = ?
|
|||||||
return r.DB().WithContext(ctx).Exec(query, purchaseID).Error
|
return r.DB().WithContext(ctx).Exec(query, purchaseID).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *PurchaseRepositoryImpl) SoftDeleteByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) error {
|
||||||
|
if len(projectFlockKandangIDs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
|
var purchaseIDs []uint
|
||||||
|
query := `
|
||||||
|
SELECT pi.purchase_id
|
||||||
|
FROM purchase_items pi
|
||||||
|
WHERE pi.project_flock_kandang_id IN (?)
|
||||||
|
GROUP BY pi.purchase_id
|
||||||
|
HAVING COUNT(*) = COUNT(CASE WHEN pi.project_flock_kandang_id IN (?) THEN 1 END)
|
||||||
|
`
|
||||||
|
if err := tx.Raw(query, projectFlockKandangIDs, projectFlockKandangIDs).Scan(&purchaseIDs).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().UTC()
|
||||||
|
if len(purchaseIDs) > 0 {
|
||||||
|
if err := tx.Model(&entity.Purchase{}).
|
||||||
|
Where("id IN (?) AND deleted_at IS NULL", purchaseIDs).
|
||||||
|
Update("deleted_at", now).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Where("purchase_id IN (?)", purchaseIDs).Delete(&entity.PurchaseItem{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteItems := tx.Where("project_flock_kandang_id IN (?)", projectFlockKandangIDs)
|
||||||
|
if len(purchaseIDs) > 0 {
|
||||||
|
deleteItems = deleteItems.Where("purchase_id NOT IN (?)", purchaseIDs)
|
||||||
|
}
|
||||||
|
return deleteItems.Delete(&entity.PurchaseItem{}).Error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (r *PurchaseRepositoryImpl) CreateItems(ctx context.Context, purchaseID uint, items []*entity.PurchaseItem) error {
|
func (r *PurchaseRepositoryImpl) CreateItems(ctx context.Context, purchaseID uint, items []*entity.PurchaseItem) error {
|
||||||
if len(items) == 0 {
|
if len(items) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ func (s *purchaseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]enti
|
|||||||
|
|
||||||
purchases, total, err := s.PurchaseRepo.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
purchases, total, err := s.PurchaseRepo.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB {
|
||||||
db = s.withRelations(db)
|
db = s.withRelations(db)
|
||||||
|
db = db.Where("purchases.deleted_at IS NULL")
|
||||||
|
|
||||||
if params.SupplierID > 0 {
|
if params.SupplierID > 0 {
|
||||||
db = db.Where("supplier_id = ?", params.SupplierID)
|
db = db.Where("supplier_id = ?", params.SupplierID)
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/common/validation"
|
"gitlab.com/mbugroup/lti-api.git/internal/common/validation"
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/response"
|
"gitlab.com/mbugroup/lti-api.git/internal/response"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/jackc/pgconn"
|
||||||
|
pgconnv5 "github.com/jackc/pgx/v5/pgconn"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ErrorHandler(c *fiber.Ctx, err error) error {
|
func ErrorHandler(c *fiber.Ctx, err error) error {
|
||||||
@@ -14,6 +17,10 @@ func ErrorHandler(c *fiber.Ctx, err error) error {
|
|||||||
return response.Error(c, fiber.StatusBadRequest, message, nil)
|
return response.Error(c, fiber.StatusBadRequest, message, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if statusCode, message := mapPgError(err); statusCode != 0 {
|
||||||
|
return response.Error(c, statusCode, message, nil)
|
||||||
|
}
|
||||||
|
|
||||||
var fiberErr *fiber.Error
|
var fiberErr *fiber.Error
|
||||||
if errors.As(err, &fiberErr) {
|
if errors.As(err, &fiberErr) {
|
||||||
return response.Error(c, fiberErr.Code, fiberErr.Message, nil)
|
return response.Error(c, fiberErr.Code, fiberErr.Message, nil)
|
||||||
@@ -26,6 +33,37 @@ func NotFoundHandler(c *fiber.Ctx) error {
|
|||||||
return response.Error(c, fiber.StatusNotFound, "Endpoint Not Found", nil)
|
return response.Error(c, fiber.StatusNotFound, "Endpoint Not Found", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapPgError(err error) (int, string) {
|
||||||
|
code, message := getPgErrorDetails(err)
|
||||||
|
if code == "" {
|
||||||
|
return 0, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch code {
|
||||||
|
case "23503":
|
||||||
|
return fiber.StatusConflict, "Data tidak bisa dihapus karena masih digunakan oleh data lain."
|
||||||
|
case "P0001":
|
||||||
|
if strings.HasPrefix(message, "Cannot soft delete") {
|
||||||
|
return fiber.StatusConflict, "Data tidak bisa dihapus karena masih digunakan oleh data lain."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPgErrorDetails(err error) (string, string) {
|
||||||
|
var pgErr *pgconn.PgError
|
||||||
|
if errors.As(err, &pgErr) {
|
||||||
|
return pgErr.Code, pgErr.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
var pgErrV5 *pgconnv5.PgError
|
||||||
|
if errors.As(err, &pgErrV5) {
|
||||||
|
return pgErrV5.Code, pgErrV5.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
func BadRequest(msg string) error {
|
func BadRequest(msg string) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, msg)
|
return fiber.NewError(fiber.StatusBadRequest, msg)
|
||||||
|
|||||||
Reference in New Issue
Block a user