Add coa purchase and vendors
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"apskel-pos-be/internal/appcontext"
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
|
||||
type ChartOfAccountProcessor interface {
|
||||
CreateChartOfAccount(ctx context.Context, req *models.CreateChartOfAccountRequest) (*models.ChartOfAccountResponse, error)
|
||||
GetChartOfAccountByID(ctx context.Context, id uuid.UUID) (*models.ChartOfAccountResponse, error)
|
||||
UpdateChartOfAccount(ctx context.Context, id uuid.UUID, req *models.UpdateChartOfAccountRequest) (*models.ChartOfAccountResponse, error)
|
||||
DeleteChartOfAccount(ctx context.Context, id uuid.UUID) error
|
||||
ListChartOfAccounts(ctx context.Context, req *models.ListChartOfAccountsRequest) ([]models.ChartOfAccountResponse, int, error)
|
||||
GetChartOfAccountsByOrganization(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]models.ChartOfAccountResponse, error)
|
||||
GetChartOfAccountsByType(ctx context.Context, organizationID uuid.UUID, chartOfAccountTypeID uuid.UUID, outletID *uuid.UUID) ([]models.ChartOfAccountResponse, error)
|
||||
CreateDefaultChartOfAccounts(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) error
|
||||
}
|
||||
|
||||
type ChartOfAccountProcessorImpl struct {
|
||||
chartOfAccountRepo ChartOfAccountRepository
|
||||
chartOfAccountTypeRepo ChartOfAccountTypeRepository
|
||||
}
|
||||
|
||||
func NewChartOfAccountProcessorImpl(chartOfAccountRepo ChartOfAccountRepository, chartOfAccountTypeRepo ChartOfAccountTypeRepository) *ChartOfAccountProcessorImpl {
|
||||
return &ChartOfAccountProcessorImpl{
|
||||
chartOfAccountRepo: chartOfAccountRepo,
|
||||
chartOfAccountTypeRepo: chartOfAccountTypeRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ChartOfAccountProcessorImpl) CreateChartOfAccount(ctx context.Context, req *models.CreateChartOfAccountRequest) (*models.ChartOfAccountResponse, error) {
|
||||
// Get organization and outlet from context
|
||||
appCtx := appcontext.FromGinContext(ctx)
|
||||
organizationID := appCtx.OrganizationID
|
||||
var outletID *uuid.UUID
|
||||
if appCtx.OutletID != uuid.Nil {
|
||||
outletID = &appCtx.OutletID
|
||||
}
|
||||
|
||||
// Check if code already exists for this organization/outlet
|
||||
existing, err := p.chartOfAccountRepo.GetByCode(ctx, organizationID, req.Code, outletID)
|
||||
if err == nil && existing != nil {
|
||||
return nil, fmt.Errorf("chart of account with code %s already exists", req.Code)
|
||||
}
|
||||
|
||||
// Validate parent exists if provided
|
||||
if req.ParentID != nil {
|
||||
_, err := p.chartOfAccountRepo.GetByID(ctx, *req.ParentID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parent chart of account not found: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate chart of account type exists
|
||||
_, err = p.chartOfAccountTypeRepo.GetByID(ctx, req.ChartOfAccountTypeID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("chart of account type not found: %w", err)
|
||||
}
|
||||
|
||||
entity := mappers.ChartOfAccountCreateRequestToEntity(req, organizationID, outletID)
|
||||
err = p.chartOfAccountRepo.Create(ctx, entity)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create chart of account: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ChartOfAccountEntityToResponse(entity), nil
|
||||
}
|
||||
|
||||
func (p *ChartOfAccountProcessorImpl) GetChartOfAccountByID(ctx context.Context, id uuid.UUID) (*models.ChartOfAccountResponse, error) {
|
||||
entity, err := p.chartOfAccountRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("chart of account not found: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ChartOfAccountEntityToResponse(entity), nil
|
||||
}
|
||||
|
||||
func (p *ChartOfAccountProcessorImpl) UpdateChartOfAccount(ctx context.Context, id uuid.UUID, req *models.UpdateChartOfAccountRequest) (*models.ChartOfAccountResponse, error) {
|
||||
entity, err := p.chartOfAccountRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("chart of account not found: %w", err)
|
||||
}
|
||||
|
||||
// Check if new code already exists (if code is being updated)
|
||||
if req.Code != nil && *req.Code != entity.Code {
|
||||
existing, err := p.chartOfAccountRepo.GetByCode(ctx, entity.OrganizationID, *req.Code, entity.OutletID)
|
||||
if err == nil && existing != nil {
|
||||
return nil, fmt.Errorf("chart of account with code %s already exists", *req.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate parent exists if provided
|
||||
if req.ParentID != nil {
|
||||
_, err := p.chartOfAccountRepo.GetByID(ctx, *req.ParentID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parent chart of account not found: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate chart of account type exists if provided
|
||||
if req.ChartOfAccountTypeID != nil {
|
||||
_, err = p.chartOfAccountTypeRepo.GetByID(ctx, *req.ChartOfAccountTypeID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("chart of account type not found: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
mappers.ChartOfAccountUpdateRequestToEntity(entity, req)
|
||||
err = p.chartOfAccountRepo.Update(ctx, entity)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update chart of account: %w", err)
|
||||
}
|
||||
|
||||
return mappers.ChartOfAccountEntityToResponse(entity), nil
|
||||
}
|
||||
|
||||
func (p *ChartOfAccountProcessorImpl) DeleteChartOfAccount(ctx context.Context, id uuid.UUID) error {
|
||||
entity, err := p.chartOfAccountRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("chart of account not found: %w", err)
|
||||
}
|
||||
|
||||
// Prevent deletion of system accounts
|
||||
if entity.IsSystem {
|
||||
return fmt.Errorf("cannot delete system chart of account")
|
||||
}
|
||||
|
||||
err = p.chartOfAccountRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete chart of account: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ChartOfAccountProcessorImpl) ListChartOfAccounts(ctx context.Context, req *models.ListChartOfAccountsRequest) ([]models.ChartOfAccountResponse, int, error) {
|
||||
// Get organization and outlet from context
|
||||
appCtx := appcontext.FromGinContext(ctx)
|
||||
organizationID := appCtx.OrganizationID
|
||||
var outletID *uuid.UUID
|
||||
if appCtx.OutletID != uuid.Nil {
|
||||
outletID = &appCtx.OutletID
|
||||
}
|
||||
|
||||
filterEntity := &entities.ChartOfAccount{
|
||||
OrganizationID: organizationID,
|
||||
OutletID: outletID,
|
||||
ChartOfAccountTypeID: *req.ChartOfAccountTypeID,
|
||||
ParentID: req.ParentID,
|
||||
}
|
||||
|
||||
entities, total, err := p.chartOfAccountRepo.List(ctx, filterEntity)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list chart of accounts: %w", err)
|
||||
}
|
||||
|
||||
responses := make([]models.ChartOfAccountResponse, len(entities))
|
||||
for i, entity := range entities {
|
||||
responses[i] = *mappers.ChartOfAccountEntityToResponse(entity)
|
||||
}
|
||||
|
||||
return responses, total, nil
|
||||
}
|
||||
|
||||
func (p *ChartOfAccountProcessorImpl) GetChartOfAccountsByOrganization(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]models.ChartOfAccountResponse, error) {
|
||||
entities, err := p.chartOfAccountRepo.GetByOrganization(ctx, organizationID, outletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get chart of accounts by organization: %w", err)
|
||||
}
|
||||
|
||||
responses := make([]models.ChartOfAccountResponse, len(entities))
|
||||
for i, entity := range entities {
|
||||
responses[i] = *mappers.ChartOfAccountEntityToResponse(entity)
|
||||
}
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
func (p *ChartOfAccountProcessorImpl) GetChartOfAccountsByType(ctx context.Context, organizationID uuid.UUID, chartOfAccountTypeID uuid.UUID, outletID *uuid.UUID) ([]models.ChartOfAccountResponse, error) {
|
||||
entities, err := p.chartOfAccountRepo.GetByType(ctx, organizationID, chartOfAccountTypeID, outletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get chart of accounts by type: %w", err)
|
||||
}
|
||||
|
||||
responses := make([]models.ChartOfAccountResponse, len(entities))
|
||||
for i, entity := range entities {
|
||||
responses[i] = *mappers.ChartOfAccountEntityToResponse(entity)
|
||||
}
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
func (p *ChartOfAccountProcessorImpl) CreateDefaultChartOfAccounts(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) error {
|
||||
// This method will be implemented to create default chart of accounts
|
||||
// based on the JSON template when a new organization/outlet is created
|
||||
// For now, we'll return nil as this is a placeholder
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user