feature/expense #13
@ -7,7 +7,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CreateExpenseRequest struct {
|
type CreateExpenseRequest struct {
|
||||||
ExpenseName string `json:"expense_name" validate:"required"`
|
|
||||||
Receiver string `json:"receiver" validate:"required"`
|
Receiver string `json:"receiver" validate:"required"`
|
||||||
TransactionDate string `json:"transaction_date" validate:"required"`
|
TransactionDate string `json:"transaction_date" validate:"required"`
|
||||||
CodeNumber string `json:"code_number" validate:"required"`
|
CodeNumber string `json:"code_number" validate:"required"`
|
||||||
@ -20,12 +19,12 @@ type CreateExpenseRequest struct {
|
|||||||
|
|
||||||
type CreateExpenseItemRequest struct {
|
type CreateExpenseItemRequest struct {
|
||||||
ChartOfAccountID string `json:"chart_of_account_id" validate:"required"`
|
ChartOfAccountID string `json:"chart_of_account_id" validate:"required"`
|
||||||
|
Item string `json:"item" validate:"required"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
Amount float64 `json:"amount" validate:"required"`
|
Amount float64 `json:"amount" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateExpenseRequest struct {
|
type UpdateExpenseRequest struct {
|
||||||
ExpenseName *string `json:"expense_name,omitempty"`
|
|
||||||
Receiver *string `json:"receiver,omitempty"`
|
Receiver *string `json:"receiver,omitempty"`
|
||||||
TransactionDate *string `json:"transaction_date,omitempty"`
|
TransactionDate *string `json:"transaction_date,omitempty"`
|
||||||
CodeNumber *string `json:"code_number,omitempty"`
|
CodeNumber *string `json:"code_number,omitempty"`
|
||||||
@ -39,6 +38,7 @@ type UpdateExpenseRequest struct {
|
|||||||
|
|
||||||
type UpdateExpenseItemRequest struct {
|
type UpdateExpenseItemRequest struct {
|
||||||
ChartOfAccountID *string `json:"chart_of_account_id,omitempty"`
|
ChartOfAccountID *string `json:"chart_of_account_id,omitempty"`
|
||||||
|
Item *string `json:"item,omitempty"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
Amount *float64 `json:"amount,omitempty"`
|
Amount *float64 `json:"amount,omitempty"`
|
||||||
}
|
}
|
||||||
@ -47,7 +47,6 @@ type ExpenseResponse struct {
|
|||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
OutletID uuid.UUID `json:"outlet_id"`
|
OutletID uuid.UUID `json:"outlet_id"`
|
||||||
ExpenseName string `json:"expense_name"`
|
|
||||||
Receiver string `json:"receiver"`
|
Receiver string `json:"receiver"`
|
||||||
TransactionDate time.Time `json:"transaction_date"`
|
TransactionDate time.Time `json:"transaction_date"`
|
||||||
CodeNumber string `json:"code_number"`
|
CodeNumber string `json:"code_number"`
|
||||||
@ -65,6 +64,7 @@ type ExpenseItemResponse struct {
|
|||||||
ExpenseID uuid.UUID `json:"expense_id"`
|
ExpenseID uuid.UUID `json:"expense_id"`
|
||||||
ChartOfAccountID uuid.UUID `json:"chart_of_account_id"`
|
ChartOfAccountID uuid.UUID `json:"chart_of_account_id"`
|
||||||
ChartOfAccountName string `json:"chart_of_account_name,omitempty"`
|
ChartOfAccountName string `json:"chart_of_account_name,omitempty"`
|
||||||
|
Item string `json:"item"`
|
||||||
Description *string `json:"description"`
|
Description *string `json:"description"`
|
||||||
Amount float64 `json:"amount"`
|
Amount float64 `json:"amount"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
|||||||
@ -129,6 +129,6 @@ type ExpenseCategoryTotal struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OperationalExpenseItem struct {
|
type OperationalExpenseItem struct {
|
||||||
Description string
|
Item string
|
||||||
Amount float64
|
Amount float64
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,6 @@ type Expense struct {
|
|||||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id"`
|
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id"`
|
||||||
OutletID uuid.UUID `gorm:"type:uuid;not null;index" json:"outlet_id"`
|
OutletID uuid.UUID `gorm:"type:uuid;not null;index" json:"outlet_id"`
|
||||||
ExpenseName string `gorm:"not null;size:255" json:"expense_name"`
|
|
||||||
Receiver string `gorm:"not null;size:255" json:"receiver"`
|
Receiver string `gorm:"not null;size:255" json:"receiver"`
|
||||||
TransactionDate time.Time `gorm:"type:date;not null" json:"transaction_date"`
|
TransactionDate time.Time `gorm:"type:date;not null" json:"transaction_date"`
|
||||||
CodeNumber string `gorm:"not null;size:50" json:"code_number"`
|
CodeNumber string `gorm:"not null;size:50" json:"code_number"`
|
||||||
|
|||||||
@ -12,6 +12,7 @@ type ExpenseItem struct {
|
|||||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||||
ExpenseID uuid.UUID `gorm:"type:uuid;not null;index" json:"expense_id"`
|
ExpenseID uuid.UUID `gorm:"type:uuid;not null;index" json:"expense_id"`
|
||||||
ChartOfAccountID uuid.UUID `gorm:"type:uuid;not null;index" json:"chart_of_account_id"`
|
ChartOfAccountID uuid.UUID `gorm:"type:uuid;not null;index" json:"chart_of_account_id"`
|
||||||
|
Item string `gorm:"not null;size:255" json:"item"`
|
||||||
Description *string `gorm:"type:text" json:"description"`
|
Description *string `gorm:"type:text" json:"description"`
|
||||||
Amount float64 `gorm:"type:decimal(15,2);not null;default:0" json:"amount"`
|
Amount float64 `gorm:"type:decimal(15,2);not null;default:0" json:"amount"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||||
|
|||||||
@ -14,7 +14,6 @@ func ExpenseEntityToModel(entity *entities.Expense) *models.Expense {
|
|||||||
ID: entity.ID,
|
ID: entity.ID,
|
||||||
OrganizationID: entity.OrganizationID,
|
OrganizationID: entity.OrganizationID,
|
||||||
OutletID: entity.OutletID,
|
OutletID: entity.OutletID,
|
||||||
ExpenseName: entity.ExpenseName,
|
|
||||||
Receiver: entity.Receiver,
|
Receiver: entity.Receiver,
|
||||||
TransactionDate: entity.TransactionDate,
|
TransactionDate: entity.TransactionDate,
|
||||||
CodeNumber: entity.CodeNumber,
|
CodeNumber: entity.CodeNumber,
|
||||||
@ -36,7 +35,6 @@ func ExpenseModelToEntity(model *models.Expense) *entities.Expense {
|
|||||||
ID: model.ID,
|
ID: model.ID,
|
||||||
OrganizationID: model.OrganizationID,
|
OrganizationID: model.OrganizationID,
|
||||||
OutletID: model.OutletID,
|
OutletID: model.OutletID,
|
||||||
ExpenseName: model.ExpenseName,
|
|
||||||
Receiver: model.Receiver,
|
Receiver: model.Receiver,
|
||||||
TransactionDate: model.TransactionDate,
|
TransactionDate: model.TransactionDate,
|
||||||
CodeNumber: model.CodeNumber,
|
CodeNumber: model.CodeNumber,
|
||||||
@ -58,7 +56,6 @@ func ExpenseEntityToResponse(entity *entities.Expense) *models.ExpenseResponse {
|
|||||||
ID: entity.ID,
|
ID: entity.ID,
|
||||||
OrganizationID: entity.OrganizationID,
|
OrganizationID: entity.OrganizationID,
|
||||||
OutletID: entity.OutletID,
|
OutletID: entity.OutletID,
|
||||||
ExpenseName: entity.ExpenseName,
|
|
||||||
Receiver: entity.Receiver,
|
Receiver: entity.Receiver,
|
||||||
TransactionDate: entity.TransactionDate,
|
TransactionDate: entity.TransactionDate,
|
||||||
CodeNumber: entity.CodeNumber,
|
CodeNumber: entity.CodeNumber,
|
||||||
@ -98,6 +95,7 @@ func ExpenseItemEntityToResponse(entity *entities.ExpenseItem) *models.ExpenseIt
|
|||||||
ID: entity.ID,
|
ID: entity.ID,
|
||||||
ExpenseID: entity.ExpenseID,
|
ExpenseID: entity.ExpenseID,
|
||||||
ChartOfAccountID: entity.ChartOfAccountID,
|
ChartOfAccountID: entity.ChartOfAccountID,
|
||||||
|
Item: entity.Item,
|
||||||
Description: entity.Description,
|
Description: entity.Description,
|
||||||
Amount: entity.Amount,
|
Amount: entity.Amount,
|
||||||
CreatedAt: entity.CreatedAt,
|
CreatedAt: entity.CreatedAt,
|
||||||
|
|||||||
@ -10,7 +10,6 @@ type Expense struct {
|
|||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
OutletID uuid.UUID `json:"outlet_id"`
|
OutletID uuid.UUID `json:"outlet_id"`
|
||||||
ExpenseName string `json:"expense_name"`
|
|
||||||
Receiver string `json:"receiver"`
|
Receiver string `json:"receiver"`
|
||||||
TransactionDate time.Time `json:"transaction_date"`
|
TransactionDate time.Time `json:"transaction_date"`
|
||||||
CodeNumber string `json:"code_number"`
|
CodeNumber string `json:"code_number"`
|
||||||
@ -26,6 +25,7 @@ type ExpenseItem struct {
|
|||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
ExpenseID uuid.UUID `json:"expense_id"`
|
ExpenseID uuid.UUID `json:"expense_id"`
|
||||||
ChartOfAccountID uuid.UUID `json:"chart_of_account_id"`
|
ChartOfAccountID uuid.UUID `json:"chart_of_account_id"`
|
||||||
|
Item string `json:"item"`
|
||||||
Description *string `json:"description"`
|
Description *string `json:"description"`
|
||||||
Amount float64 `json:"amount"`
|
Amount float64 `json:"amount"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
@ -36,7 +36,6 @@ type ExpenseResponse struct {
|
|||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
OutletID uuid.UUID `json:"outlet_id"`
|
OutletID uuid.UUID `json:"outlet_id"`
|
||||||
ExpenseName string `json:"expense_name"`
|
|
||||||
Receiver string `json:"receiver"`
|
Receiver string `json:"receiver"`
|
||||||
TransactionDate time.Time `json:"transaction_date"`
|
TransactionDate time.Time `json:"transaction_date"`
|
||||||
CodeNumber string `json:"code_number"`
|
CodeNumber string `json:"code_number"`
|
||||||
@ -54,6 +53,7 @@ type ExpenseItemResponse struct {
|
|||||||
ExpenseID uuid.UUID `json:"expense_id"`
|
ExpenseID uuid.UUID `json:"expense_id"`
|
||||||
ChartOfAccountID uuid.UUID `json:"chart_of_account_id"`
|
ChartOfAccountID uuid.UUID `json:"chart_of_account_id"`
|
||||||
ChartOfAccountName string `json:"chart_of_account_name,omitempty"`
|
ChartOfAccountName string `json:"chart_of_account_name,omitempty"`
|
||||||
|
Item string `json:"item"`
|
||||||
Description *string `json:"description"`
|
Description *string `json:"description"`
|
||||||
Amount float64 `json:"amount"`
|
Amount float64 `json:"amount"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
@ -61,7 +61,6 @@ type ExpenseItemResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreateExpenseRequest struct {
|
type CreateExpenseRequest struct {
|
||||||
ExpenseName string `json:"expense_name"`
|
|
||||||
Receiver string `json:"receiver"`
|
Receiver string `json:"receiver"`
|
||||||
TransactionDate string `json:"transaction_date"`
|
TransactionDate string `json:"transaction_date"`
|
||||||
CodeNumber string `json:"code_number"`
|
CodeNumber string `json:"code_number"`
|
||||||
@ -74,12 +73,12 @@ type CreateExpenseRequest struct {
|
|||||||
|
|
||||||
type CreateExpenseItemRequest struct {
|
type CreateExpenseItemRequest struct {
|
||||||
ChartOfAccountID string `json:"chart_of_account_id"`
|
ChartOfAccountID string `json:"chart_of_account_id"`
|
||||||
|
Item string `json:"item"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
Amount float64 `json:"amount"`
|
Amount float64 `json:"amount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateExpenseRequest struct {
|
type UpdateExpenseRequest struct {
|
||||||
ExpenseName *string `json:"expense_name,omitempty"`
|
|
||||||
Receiver *string `json:"receiver,omitempty"`
|
Receiver *string `json:"receiver,omitempty"`
|
||||||
TransactionDate *string `json:"transaction_date,omitempty"`
|
TransactionDate *string `json:"transaction_date,omitempty"`
|
||||||
CodeNumber *string `json:"code_number,omitempty"`
|
CodeNumber *string `json:"code_number,omitempty"`
|
||||||
@ -93,6 +92,7 @@ type UpdateExpenseRequest struct {
|
|||||||
|
|
||||||
type UpdateExpenseItemRequest struct {
|
type UpdateExpenseItemRequest struct {
|
||||||
ChartOfAccountID *string `json:"chart_of_account_id,omitempty"`
|
ChartOfAccountID *string `json:"chart_of_account_id,omitempty"`
|
||||||
|
Item *string `json:"item,omitempty"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
Amount *float64 `json:"amount,omitempty"`
|
Amount *float64 `json:"amount,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -498,7 +498,7 @@ func (p *AnalyticsProcessorImpl) GetProfitLossAnalytics(ctx context.Context, req
|
|||||||
var opsTotal float64
|
var opsTotal float64
|
||||||
for i, item := range result.OperationalExpenseItems {
|
for i, item := range result.OperationalExpenseItems {
|
||||||
opsItems[i] = models.OperationalExpenseItem{
|
opsItems[i] = models.OperationalExpenseItem{
|
||||||
Item: item.Description,
|
Item: item.Item,
|
||||||
Nominal: item.Amount,
|
Nominal: item.Amount,
|
||||||
}
|
}
|
||||||
opsTotal += item.Amount
|
opsTotal += item.Amount
|
||||||
|
|||||||
@ -44,7 +44,6 @@ func (p *ExpenseProcessorImpl) CreateExpense(ctx context.Context, organizationID
|
|||||||
expenseEntity := &entities.Expense{
|
expenseEntity := &entities.Expense{
|
||||||
OrganizationID: organizationID,
|
OrganizationID: organizationID,
|
||||||
OutletID: outletID,
|
OutletID: outletID,
|
||||||
ExpenseName: req.ExpenseName,
|
|
||||||
Receiver: req.Receiver,
|
Receiver: req.Receiver,
|
||||||
TransactionDate: transactionDate,
|
TransactionDate: transactionDate,
|
||||||
CodeNumber: req.CodeNumber,
|
CodeNumber: req.CodeNumber,
|
||||||
@ -67,6 +66,7 @@ func (p *ExpenseProcessorImpl) CreateExpense(ctx context.Context, organizationID
|
|||||||
itemEntity := &entities.ExpenseItem{
|
itemEntity := &entities.ExpenseItem{
|
||||||
ExpenseID: expenseEntity.ID,
|
ExpenseID: expenseEntity.ID,
|
||||||
ChartOfAccountID: chartOfAccountID,
|
ChartOfAccountID: chartOfAccountID,
|
||||||
|
Item: itemReq.Item,
|
||||||
Description: itemReq.Description,
|
Description: itemReq.Description,
|
||||||
Amount: itemReq.Amount,
|
Amount: itemReq.Amount,
|
||||||
}
|
}
|
||||||
@ -91,9 +91,6 @@ func (p *ExpenseProcessorImpl) UpdateExpense(ctx context.Context, id, organizati
|
|||||||
return nil, fmt.Errorf("expense not found: %w", err)
|
return nil, fmt.Errorf("expense not found: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.ExpenseName != nil {
|
|
||||||
expenseEntity.ExpenseName = *req.ExpenseName
|
|
||||||
}
|
|
||||||
if req.Receiver != nil {
|
if req.Receiver != nil {
|
||||||
expenseEntity.Receiver = *req.Receiver
|
expenseEntity.Receiver = *req.Receiver
|
||||||
}
|
}
|
||||||
@ -146,10 +143,15 @@ func (p *ExpenseProcessorImpl) UpdateExpense(ctx context.Context, id, organizati
|
|||||||
if itemReq.Amount != nil {
|
if itemReq.Amount != nil {
|
||||||
amount = *itemReq.Amount
|
amount = *itemReq.Amount
|
||||||
}
|
}
|
||||||
|
item := ""
|
||||||
|
if itemReq.Item != nil {
|
||||||
|
item = *itemReq.Item
|
||||||
|
}
|
||||||
|
|
||||||
itemEntity := &entities.ExpenseItem{
|
itemEntity := &entities.ExpenseItem{
|
||||||
ExpenseID: expenseEntity.ID,
|
ExpenseID: expenseEntity.ID,
|
||||||
ChartOfAccountID: chartOfAccountID,
|
ChartOfAccountID: chartOfAccountID,
|
||||||
|
Item: item,
|
||||||
Description: itemReq.Description,
|
Description: itemReq.Description,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -531,7 +531,7 @@ func (r *AnalyticsRepositoryImpl) getOperationalExpenseItems(ctx context.Context
|
|||||||
|
|
||||||
query := r.db.WithContext(ctx).
|
query := r.db.WithContext(ctx).
|
||||||
Table("expense_items ei").
|
Table("expense_items ei").
|
||||||
Select(`COALESCE(ei.description, coa.name) as description, COALESCE(SUM(ei.amount), 0) as amount`).
|
Select(`COALESCE(NULLIF(ei.item, ''), ei.description, coa.name) as item, COALESCE(SUM(ei.amount), 0) as amount`).
|
||||||
Joins("JOIN expenses e ON ei.expense_id = e.id").
|
Joins("JOIN expenses e ON ei.expense_id = e.id").
|
||||||
Joins("JOIN chart_of_accounts coa ON ei.chart_of_account_id = coa.id").
|
Joins("JOIN chart_of_accounts coa ON ei.chart_of_account_id = coa.id").
|
||||||
Where("e.organization_id = ?", organizationID).
|
Where("e.organization_id = ?", organizationID).
|
||||||
@ -542,7 +542,7 @@ func (r *AnalyticsRepositoryImpl) getOperationalExpenseItems(ctx context.Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := query.
|
err := query.
|
||||||
Group("COALESCE(ei.description, coa.name)").
|
Group("COALESCE(NULLIF(ei.item, ''), ei.description, coa.name)").
|
||||||
Order("amount DESC").
|
Order("amount DESC").
|
||||||
Scan(&results).Error
|
Scan(&results).Error
|
||||||
|
|
||||||
|
|||||||
@ -68,8 +68,17 @@ func (r *ExpenseRepositoryImpl) List(ctx context.Context, organizationID uuid.UU
|
|||||||
case "search":
|
case "search":
|
||||||
if searchStr, ok := value.(string); ok && searchStr != "" {
|
if searchStr, ok := value.(string); ok && searchStr != "" {
|
||||||
searchPattern := "%" + strings.ToLower(searchStr) + "%"
|
searchPattern := "%" + strings.ToLower(searchStr) + "%"
|
||||||
query = query.Where("LOWER(expense_name) LIKE ? OR LOWER(receiver) LIKE ? OR LOWER(code_number) LIKE ? OR LOWER(description) LIKE ?",
|
query = query.Where(`
|
||||||
searchPattern, searchPattern, searchPattern, searchPattern)
|
LOWER(receiver) LIKE ?
|
||||||
|
OR LOWER(code_number) LIKE ?
|
||||||
|
OR LOWER(description) LIKE ?
|
||||||
|
OR EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM expense_items ei
|
||||||
|
WHERE ei.expense_id = expenses.id
|
||||||
|
AND LOWER(ei.item) LIKE ?
|
||||||
|
)
|
||||||
|
`, searchPattern, searchPattern, searchPattern, searchPattern)
|
||||||
}
|
}
|
||||||
case "outlet_id":
|
case "outlet_id":
|
||||||
if outletID, ok := value.(uuid.UUID); ok {
|
if outletID, ok := value.(uuid.UUID); ok {
|
||||||
|
|||||||
@ -12,7 +12,6 @@ func CreateExpenseRequestToModel(req *contract.CreateExpenseRequest) *models.Cre
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &models.CreateExpenseRequest{
|
return &models.CreateExpenseRequest{
|
||||||
ExpenseName: req.ExpenseName,
|
|
||||||
Receiver: req.Receiver,
|
Receiver: req.Receiver,
|
||||||
TransactionDate: req.TransactionDate,
|
TransactionDate: req.TransactionDate,
|
||||||
CodeNumber: req.CodeNumber,
|
CodeNumber: req.CodeNumber,
|
||||||
@ -27,6 +26,7 @@ func CreateExpenseRequestToModel(req *contract.CreateExpenseRequest) *models.Cre
|
|||||||
func CreateExpenseItemRequestToModel(req *contract.CreateExpenseItemRequest) models.CreateExpenseItemRequest {
|
func CreateExpenseItemRequestToModel(req *contract.CreateExpenseItemRequest) models.CreateExpenseItemRequest {
|
||||||
return models.CreateExpenseItemRequest{
|
return models.CreateExpenseItemRequest{
|
||||||
ChartOfAccountID: req.ChartOfAccountID,
|
ChartOfAccountID: req.ChartOfAccountID,
|
||||||
|
Item: req.Item,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
Amount: req.Amount,
|
Amount: req.Amount,
|
||||||
}
|
}
|
||||||
@ -34,7 +34,6 @@ func CreateExpenseItemRequestToModel(req *contract.CreateExpenseItemRequest) mod
|
|||||||
|
|
||||||
func UpdateExpenseRequestToModel(req *contract.UpdateExpenseRequest) *models.UpdateExpenseRequest {
|
func UpdateExpenseRequestToModel(req *contract.UpdateExpenseRequest) *models.UpdateExpenseRequest {
|
||||||
modelReq := &models.UpdateExpenseRequest{
|
modelReq := &models.UpdateExpenseRequest{
|
||||||
ExpenseName: req.ExpenseName,
|
|
||||||
Receiver: req.Receiver,
|
Receiver: req.Receiver,
|
||||||
TransactionDate: req.TransactionDate,
|
TransactionDate: req.TransactionDate,
|
||||||
CodeNumber: req.CodeNumber,
|
CodeNumber: req.CodeNumber,
|
||||||
@ -59,6 +58,7 @@ func UpdateExpenseRequestToModel(req *contract.UpdateExpenseRequest) *models.Upd
|
|||||||
func UpdateExpenseItemRequestToModel(req *contract.UpdateExpenseItemRequest) models.UpdateExpenseItemRequest {
|
func UpdateExpenseItemRequestToModel(req *contract.UpdateExpenseItemRequest) models.UpdateExpenseItemRequest {
|
||||||
return models.UpdateExpenseItemRequest{
|
return models.UpdateExpenseItemRequest{
|
||||||
ChartOfAccountID: req.ChartOfAccountID,
|
ChartOfAccountID: req.ChartOfAccountID,
|
||||||
|
Item: req.Item,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
Amount: req.Amount,
|
Amount: req.Amount,
|
||||||
}
|
}
|
||||||
@ -89,7 +89,6 @@ func ExpenseModelResponseToResponse(expense *models.ExpenseResponse) *contract.E
|
|||||||
ID: expense.ID,
|
ID: expense.ID,
|
||||||
OrganizationID: expense.OrganizationID,
|
OrganizationID: expense.OrganizationID,
|
||||||
OutletID: expense.OutletID,
|
OutletID: expense.OutletID,
|
||||||
ExpenseName: expense.ExpenseName,
|
|
||||||
Receiver: expense.Receiver,
|
Receiver: expense.Receiver,
|
||||||
TransactionDate: expense.TransactionDate,
|
TransactionDate: expense.TransactionDate,
|
||||||
CodeNumber: expense.CodeNumber,
|
CodeNumber: expense.CodeNumber,
|
||||||
@ -109,6 +108,7 @@ func ExpenseItemModelResponseToResponse(item *models.ExpenseItemResponse) contra
|
|||||||
ExpenseID: item.ExpenseID,
|
ExpenseID: item.ExpenseID,
|
||||||
ChartOfAccountID: item.ChartOfAccountID,
|
ChartOfAccountID: item.ChartOfAccountID,
|
||||||
ChartOfAccountName: item.ChartOfAccountName,
|
ChartOfAccountName: item.ChartOfAccountName,
|
||||||
|
Item: item.Item,
|
||||||
Description: item.Description,
|
Description: item.Description,
|
||||||
Amount: item.Amount,
|
Amount: item.Amount,
|
||||||
CreatedAt: item.CreatedAt,
|
CreatedAt: item.CreatedAt,
|
||||||
|
|||||||
@ -28,10 +28,6 @@ func (v *ExpenseValidatorImpl) ValidateCreateExpenseRequest(req *contract.Create
|
|||||||
return errors.New("request body is required"), constants.MissingFieldErrorCode
|
return errors.New("request body is required"), constants.MissingFieldErrorCode
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.TrimSpace(req.ExpenseName) == "" {
|
|
||||||
return errors.New("expense_name is required"), constants.MissingFieldErrorCode
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.TrimSpace(req.Receiver) == "" {
|
if strings.TrimSpace(req.Receiver) == "" {
|
||||||
return errors.New("receiver is required"), constants.MissingFieldErrorCode
|
return errors.New("receiver is required"), constants.MissingFieldErrorCode
|
||||||
}
|
}
|
||||||
@ -68,6 +64,9 @@ func (v *ExpenseValidatorImpl) ValidateCreateExpenseRequest(req *contract.Create
|
|||||||
if strings.TrimSpace(item.ChartOfAccountID) == "" {
|
if strings.TrimSpace(item.ChartOfAccountID) == "" {
|
||||||
return fmt.Errorf("item %d: chart_of_account_id is required", i), constants.MissingFieldErrorCode
|
return fmt.Errorf("item %d: chart_of_account_id is required", i), constants.MissingFieldErrorCode
|
||||||
}
|
}
|
||||||
|
if strings.TrimSpace(item.Item) == "" {
|
||||||
|
return fmt.Errorf("item %d: item is required", i), constants.MissingFieldErrorCode
|
||||||
|
}
|
||||||
if _, err := uuid.Parse(item.ChartOfAccountID); err != nil {
|
if _, err := uuid.Parse(item.ChartOfAccountID); err != nil {
|
||||||
return fmt.Errorf("item %d: chart_of_account_id must be a valid UUID", i), constants.MalformedFieldErrorCode
|
return fmt.Errorf("item %d: chart_of_account_id must be a valid UUID", i), constants.MalformedFieldErrorCode
|
||||||
}
|
}
|
||||||
@ -84,10 +83,6 @@ func (v *ExpenseValidatorImpl) ValidateUpdateExpenseRequest(req *contract.Update
|
|||||||
return errors.New("request body is required"), constants.MissingFieldErrorCode
|
return errors.New("request body is required"), constants.MissingFieldErrorCode
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.ExpenseName != nil && strings.TrimSpace(*req.ExpenseName) == "" {
|
|
||||||
return errors.New("expense_name cannot be empty"), constants.MalformedFieldErrorCode
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Receiver != nil && strings.TrimSpace(*req.Receiver) == "" {
|
if req.Receiver != nil && strings.TrimSpace(*req.Receiver) == "" {
|
||||||
return errors.New("receiver cannot be empty"), constants.MalformedFieldErrorCode
|
return errors.New("receiver cannot be empty"), constants.MalformedFieldErrorCode
|
||||||
}
|
}
|
||||||
@ -123,6 +118,9 @@ func (v *ExpenseValidatorImpl) ValidateUpdateExpenseRequest(req *contract.Update
|
|||||||
return fmt.Errorf("item %d: chart_of_account_id must be a valid UUID", i), constants.MalformedFieldErrorCode
|
return fmt.Errorf("item %d: chart_of_account_id must be a valid UUID", i), constants.MalformedFieldErrorCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if item.Item != nil && strings.TrimSpace(*item.Item) == "" {
|
||||||
|
return fmt.Errorf("item %d: item cannot be empty", i), constants.MalformedFieldErrorCode
|
||||||
|
}
|
||||||
if item.Amount != nil && *item.Amount <= 0 {
|
if item.Amount != nil && *item.Amount <= 0 {
|
||||||
return fmt.Errorf("item %d: amount must be greater than 0", i), constants.MalformedFieldErrorCode
|
return fmt.Errorf("item %d: amount must be greater than 0", i), constants.MalformedFieldErrorCode
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,16 @@
|
|||||||
DROP INDEX IF EXISTS idx_expenses_expense_name;
|
ALTER TABLE expenses ADD COLUMN IF NOT EXISTS expense_name VARCHAR(255) NOT NULL DEFAULT '';
|
||||||
ALTER TABLE expenses DROP COLUMN expense_name;
|
|
||||||
|
UPDATE expenses e
|
||||||
|
SET expense_name = first_item.item
|
||||||
|
FROM (
|
||||||
|
SELECT DISTINCT ON (expense_id) expense_id, item
|
||||||
|
FROM expense_items
|
||||||
|
WHERE COALESCE(item, '') != ''
|
||||||
|
ORDER BY expense_id, created_at ASC
|
||||||
|
) first_item
|
||||||
|
WHERE e.id = first_item.expense_id
|
||||||
|
AND COALESCE(e.expense_name, '') = '';
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_expenses_expense_name ON expenses(expense_name);
|
||||||
|
DROP INDEX IF EXISTS idx_expense_items_item;
|
||||||
|
ALTER TABLE expense_items DROP COLUMN IF EXISTS item;
|
||||||
|
|||||||
@ -1,2 +1,21 @@
|
|||||||
ALTER TABLE expenses ADD COLUMN expense_name VARCHAR(255) NOT NULL DEFAULT '';
|
ALTER TABLE expense_items ADD COLUMN IF NOT EXISTS item VARCHAR(255) NOT NULL DEFAULT '';
|
||||||
CREATE INDEX idx_expenses_expense_name ON expenses(expense_name);
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'expenses'
|
||||||
|
AND column_name = 'expense_name'
|
||||||
|
) THEN
|
||||||
|
UPDATE expense_items ei
|
||||||
|
SET item = e.expense_name
|
||||||
|
FROM expenses e
|
||||||
|
WHERE ei.expense_id = e.id
|
||||||
|
AND COALESCE(ei.item, '') = '';
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS idx_expenses_expense_name;
|
||||||
|
ALTER TABLE expenses DROP COLUMN IF EXISTS expense_name;
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_expense_items_item ON expense_items(item);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user