package processor import ( "context" "fmt" "apskel-pos-be/internal/entities" "apskel-pos-be/internal/mappers" "apskel-pos-be/internal/models" "github.com/google/uuid" ) type VendorProcessor interface { CreateVendor(ctx context.Context, organizationID uuid.UUID, req *models.CreateVendorRequest) (*models.VendorResponse, error) UpdateVendor(ctx context.Context, id, organizationID uuid.UUID, req *models.UpdateVendorRequest) (*models.VendorResponse, error) DeleteVendor(ctx context.Context, id, organizationID uuid.UUID) error GetVendorByID(ctx context.Context, id, organizationID uuid.UUID) (*models.VendorResponse, error) ListVendors(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, page, limit int) ([]*models.VendorResponse, int, error) GetActiveVendors(ctx context.Context, organizationID uuid.UUID) ([]*models.VendorResponse, error) } type VendorProcessorImpl struct { vendorRepo VendorRepository } func NewVendorProcessorImpl(vendorRepo VendorRepository) *VendorProcessorImpl { return &VendorProcessorImpl{ vendorRepo: vendorRepo, } } func (p *VendorProcessorImpl) CreateVendor(ctx context.Context, organizationID uuid.UUID, req *models.CreateVendorRequest) (*models.VendorResponse, error) { // Check if vendor with same name already exists in organization if req.Name != "" { existingVendor, err := p.vendorRepo.GetByName(ctx, req.Name, organizationID) if err == nil && existingVendor != nil { return nil, fmt.Errorf("vendor with name %s already exists in this organization", req.Name) } } // Check if vendor with same email already exists in organization if req.Email != nil && *req.Email != "" { existingVendor, err := p.vendorRepo.GetByEmail(ctx, *req.Email, organizationID) if err == nil && existingVendor != nil { return nil, fmt.Errorf("vendor with email %s already exists in this organization", *req.Email) } } vendorEntity := &entities.Vendor{ OrganizationID: organizationID, Name: req.Name, Email: req.Email, PhoneNumber: req.PhoneNumber, Address: req.Address, ContactPerson: req.ContactPerson, TaxNumber: req.TaxNumber, PaymentTerms: req.PaymentTerms, Notes: req.Notes, IsActive: true, // Default to active } if req.IsActive != nil { vendorEntity.IsActive = *req.IsActive } err := p.vendorRepo.Create(ctx, vendorEntity) if err != nil { return nil, fmt.Errorf("failed to create vendor: %w", err) } return mappers.VendorEntityToResponse(vendorEntity), nil } func (p *VendorProcessorImpl) UpdateVendor(ctx context.Context, id, organizationID uuid.UUID, req *models.UpdateVendorRequest) (*models.VendorResponse, error) { vendorEntity, err := p.vendorRepo.GetByIDAndOrganizationID(ctx, id, organizationID) if err != nil { return nil, fmt.Errorf("vendor not found: %w", err) } // Check if vendor with same name already exists (excluding current vendor) if req.Name != nil && *req.Name != "" && *req.Name != vendorEntity.Name { existingVendor, err := p.vendorRepo.GetByName(ctx, *req.Name, organizationID) if err == nil && existingVendor != nil && existingVendor.ID != id { return nil, fmt.Errorf("vendor with name %s already exists in this organization", *req.Name) } } // Check if vendor with same email already exists (excluding current vendor) if req.Email != nil && *req.Email != "" && (vendorEntity.Email == nil || *req.Email != *vendorEntity.Email) { existingVendor, err := p.vendorRepo.GetByEmail(ctx, *req.Email, organizationID) if err == nil && existingVendor != nil && existingVendor.ID != id { return nil, fmt.Errorf("vendor with email %s already exists in this organization", *req.Email) } } // Update fields if req.Name != nil { vendorEntity.Name = *req.Name } if req.Email != nil { vendorEntity.Email = req.Email } if req.PhoneNumber != nil { vendorEntity.PhoneNumber = req.PhoneNumber } if req.Address != nil { vendorEntity.Address = req.Address } if req.ContactPerson != nil { vendorEntity.ContactPerson = req.ContactPerson } if req.TaxNumber != nil { vendorEntity.TaxNumber = req.TaxNumber } if req.PaymentTerms != nil { vendorEntity.PaymentTerms = req.PaymentTerms } if req.Notes != nil { vendorEntity.Notes = req.Notes } if req.IsActive != nil { vendorEntity.IsActive = *req.IsActive } err = p.vendorRepo.Update(ctx, vendorEntity) if err != nil { return nil, fmt.Errorf("failed to update vendor: %w", err) } return mappers.VendorEntityToResponse(vendorEntity), nil } func (p *VendorProcessorImpl) DeleteVendor(ctx context.Context, id, organizationID uuid.UUID) error { _, err := p.vendorRepo.GetByIDAndOrganizationID(ctx, id, organizationID) if err != nil { return fmt.Errorf("vendor not found: %w", err) } err = p.vendorRepo.Delete(ctx, id) if err != nil { return fmt.Errorf("failed to delete vendor: %w", err) } return nil } func (p *VendorProcessorImpl) GetVendorByID(ctx context.Context, id, organizationID uuid.UUID) (*models.VendorResponse, error) { vendorEntity, err := p.vendorRepo.GetByIDAndOrganizationID(ctx, id, organizationID) if err != nil { return nil, fmt.Errorf("vendor not found: %w", err) } return mappers.VendorEntityToResponse(vendorEntity), nil } func (p *VendorProcessorImpl) ListVendors(ctx context.Context, organizationID uuid.UUID, filters map[string]interface{}, page, limit int) ([]*models.VendorResponse, int, error) { offset := (page - 1) * limit vendorEntities, total, err := p.vendorRepo.List(ctx, organizationID, filters, limit, offset) if err != nil { return nil, 0, fmt.Errorf("failed to list vendors: %w", err) } vendorResponses := mappers.VendorEntitiesToResponses(vendorEntities) totalPages := int((total + int64(limit) - 1) / int64(limit)) return vendorResponses, totalPages, nil } func (p *VendorProcessorImpl) GetActiveVendors(ctx context.Context, organizationID uuid.UUID) ([]*models.VendorResponse, error) { vendorEntities, err := p.vendorRepo.GetActiveVendors(ctx, organizationID) if err != nil { return nil, fmt.Errorf("failed to get active vendors: %w", err) } return mappers.VendorEntitiesToResponses(vendorEntities), nil }