2025-09-12 01:12:11 +07:00

178 lines
6.0 KiB
Go

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
}