Update expense for product category (non-inventory type)
This commit is contained in:
@@ -23,12 +23,14 @@ type ExpenseProcessor interface {
|
||||
}
|
||||
|
||||
type ExpenseProcessorImpl struct {
|
||||
expenseRepo ExpenseRepository
|
||||
expenseRepo ExpenseRepository
|
||||
purchaseCategoryRepo PurchaseCategoryRepository
|
||||
}
|
||||
|
||||
func NewExpenseProcessorImpl(expenseRepo ExpenseRepository) *ExpenseProcessorImpl {
|
||||
func NewExpenseProcessorImpl(expenseRepo ExpenseRepository, purchaseCategoryRepo PurchaseCategoryRepository) *ExpenseProcessorImpl {
|
||||
return &ExpenseProcessorImpl{
|
||||
expenseRepo: expenseRepo,
|
||||
expenseRepo: expenseRepo,
|
||||
purchaseCategoryRepo: purchaseCategoryRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +50,30 @@ func (p *ExpenseProcessorImpl) CreateExpense(ctx context.Context, organizationID
|
||||
status = *req.Status
|
||||
}
|
||||
|
||||
items := make([]entities.ExpenseItem, len(req.Items))
|
||||
for i, itemReq := range req.Items {
|
||||
chartOfAccountID, err := uuid.Parse(itemReq.ChartOfAccountID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid chart_of_account_id for item: %w", err)
|
||||
}
|
||||
|
||||
purchaseCategoryID, err := uuid.Parse(itemReq.PurchaseCategoryID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid purchase_category_id for item: %w", err)
|
||||
}
|
||||
if err := p.validateNonInventoryPurchaseCategory(ctx, purchaseCategoryID, organizationID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items[i] = entities.ExpenseItem{
|
||||
ChartOfAccountID: chartOfAccountID,
|
||||
PurchaseCategoryID: purchaseCategoryID,
|
||||
Item: itemReq.Item,
|
||||
Description: itemReq.Description,
|
||||
Amount: itemReq.Amount,
|
||||
}
|
||||
}
|
||||
|
||||
expenseEntity := &entities.Expense{
|
||||
OrganizationID: organizationID,
|
||||
OutletID: outletID,
|
||||
@@ -65,21 +91,10 @@ func (p *ExpenseProcessorImpl) CreateExpense(ctx context.Context, organizationID
|
||||
return nil, fmt.Errorf("failed to create expense: %w", err)
|
||||
}
|
||||
|
||||
for _, itemReq := range req.Items {
|
||||
chartOfAccountID, err := uuid.Parse(itemReq.ChartOfAccountID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid chart_of_account_id for item: %w", err)
|
||||
}
|
||||
for i := range items {
|
||||
items[i].ExpenseID = expenseEntity.ID
|
||||
|
||||
itemEntity := &entities.ExpenseItem{
|
||||
ExpenseID: expenseEntity.ID,
|
||||
ChartOfAccountID: chartOfAccountID,
|
||||
Item: itemReq.Item,
|
||||
Description: itemReq.Description,
|
||||
Amount: itemReq.Amount,
|
||||
}
|
||||
|
||||
err = p.expenseRepo.CreateItem(ctx, itemEntity)
|
||||
err = p.expenseRepo.CreateItem(ctx, &items[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create expense item: %w", err)
|
||||
}
|
||||
@@ -135,13 +150,10 @@ func (p *ExpenseProcessorImpl) UpdateExpense(ctx context.Context, id, organizati
|
||||
expenseEntity.Reserved1 = req.Reserved1
|
||||
}
|
||||
|
||||
var items []entities.ExpenseItem
|
||||
if req.Items != nil {
|
||||
err = p.expenseRepo.DeleteItemsByExpenseID(ctx, expenseEntity.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to delete existing items: %w", err)
|
||||
}
|
||||
|
||||
for _, itemReq := range req.Items {
|
||||
items = make([]entities.ExpenseItem, len(req.Items))
|
||||
for i, itemReq := range req.Items {
|
||||
chartOfAccountID := uuid.Nil
|
||||
if itemReq.ChartOfAccountID != nil {
|
||||
chartOfAccountID, err = uuid.Parse(*itemReq.ChartOfAccountID)
|
||||
@@ -150,6 +162,17 @@ func (p *ExpenseProcessorImpl) UpdateExpense(ctx context.Context, id, organizati
|
||||
}
|
||||
}
|
||||
|
||||
if itemReq.PurchaseCategoryID == nil {
|
||||
return nil, fmt.Errorf("purchase_category_id is required for item")
|
||||
}
|
||||
purchaseCategoryID, err := uuid.Parse(*itemReq.PurchaseCategoryID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid purchase_category_id for item: %w", err)
|
||||
}
|
||||
if err := p.validateNonInventoryPurchaseCategory(ctx, purchaseCategoryID, organizationID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
amount := 0.0
|
||||
if itemReq.Amount != nil {
|
||||
amount = *itemReq.Amount
|
||||
@@ -159,15 +182,23 @@ func (p *ExpenseProcessorImpl) UpdateExpense(ctx context.Context, id, organizati
|
||||
item = *itemReq.Item
|
||||
}
|
||||
|
||||
itemEntity := &entities.ExpenseItem{
|
||||
ExpenseID: expenseEntity.ID,
|
||||
ChartOfAccountID: chartOfAccountID,
|
||||
Item: item,
|
||||
Description: itemReq.Description,
|
||||
Amount: amount,
|
||||
items[i] = entities.ExpenseItem{
|
||||
ExpenseID: expenseEntity.ID,
|
||||
ChartOfAccountID: chartOfAccountID,
|
||||
PurchaseCategoryID: purchaseCategoryID,
|
||||
Item: item,
|
||||
Description: itemReq.Description,
|
||||
Amount: amount,
|
||||
}
|
||||
}
|
||||
|
||||
err = p.expenseRepo.CreateItem(ctx, itemEntity)
|
||||
err = p.expenseRepo.DeleteItemsByExpenseID(ctx, expenseEntity.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to delete existing items: %w", err)
|
||||
}
|
||||
|
||||
for i := range items {
|
||||
err = p.expenseRepo.CreateItem(ctx, &items[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create expense item: %w", err)
|
||||
}
|
||||
@@ -252,6 +283,18 @@ func (p *ExpenseProcessorImpl) GetExpenseAnalytics(ctx context.Context, req *mod
|
||||
categoryData := make([]models.ExpenseAnalyticsCategoryData, len(result.CategoryData))
|
||||
for i, item := range result.CategoryData {
|
||||
categoryData[i] = models.ExpenseAnalyticsCategoryData{
|
||||
PurchaseCategoryID: item.PurchaseCategoryID,
|
||||
PurchaseCategoryName: item.PurchaseCategoryName,
|
||||
PurchaseCategoryType: item.PurchaseCategoryType,
|
||||
TotalAmount: item.TotalAmount,
|
||||
ExpenseCount: item.ExpenseCount,
|
||||
ItemCount: item.ItemCount,
|
||||
}
|
||||
}
|
||||
|
||||
chartOfAccountData := make([]models.ExpenseAnalyticsChartOfAccountData, len(result.ChartOfAccountData))
|
||||
for i, item := range result.ChartOfAccountData {
|
||||
chartOfAccountData[i] = models.ExpenseAnalyticsChartOfAccountData{
|
||||
ChartOfAccountID: item.ChartOfAccountID,
|
||||
ChartOfAccountName: item.ChartOfAccountName,
|
||||
TotalAmount: item.TotalAmount,
|
||||
@@ -284,8 +327,26 @@ func (p *ExpenseProcessorImpl) GetExpenseAnalytics(ctx context.Context, req *mod
|
||||
TotalCategories: result.Summary.TotalCategories,
|
||||
TotalItems: result.Summary.TotalItems,
|
||||
},
|
||||
Data: data,
|
||||
CategoryData: categoryData,
|
||||
ItemData: itemData,
|
||||
Data: data,
|
||||
CategoryData: categoryData,
|
||||
ChartOfAccountData: chartOfAccountData,
|
||||
ItemData: itemData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *ExpenseProcessorImpl) validateNonInventoryPurchaseCategory(ctx context.Context, categoryID, organizationID uuid.UUID) error {
|
||||
category, err := p.purchaseCategoryRepo.GetByIDAndOrganizationID(ctx, categoryID, organizationID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("purchase category not found: %w", err)
|
||||
}
|
||||
|
||||
if !category.IsActive {
|
||||
return fmt.Errorf("purchase category is inactive")
|
||||
}
|
||||
|
||||
if category.Type != entities.PurchaseCategoryTypeNonInventory {
|
||||
return fmt.Errorf("purchase category must be non_inventory")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user