Files
tm_back/internal/company/form.go
T
Mazyar 89faa08b1c
continuous-integration/drone/push Build is passing
Add functionality to manage external links for companies
- Introduced the ability to append external links to company profiles through a new API endpoint.
- Enhanced the `Company` entity to include a `Links` field for storing external resource links.
- Created `AddLinksForm` for validating incoming link data and implemented corresponding logic in the service layer.
- Added error handling for link validation, ensuring only valid URLs are accepted and limiting the number of links to 20.
- Implemented unit tests for link management functions, including sanitization and merging of links.
- Updated relevant API documentation to reflect the new functionality.

This update significantly enhances the company management capabilities by allowing the addition of external links, improving the overall user experience and data richness in company profiles.
2026-07-06 00:05:48 +03:30

243 lines
11 KiB
Go

package company
import "tm/pkg/response"
// CompanyForm represents the form for creating/updating a new company
type (
CompanyForm struct {
Name string `json:"name" valid:"required,length(2|200)" example:"Opplens"`
Type string `json:"type" valid:"required,in(private|public|government|ngo|startup)" example:"private"`
RegistrationNumber string `json:"registration_number" valid:"optional,length(5|50)" example:"1234567890"`
TaxID string `json:"tax_id" valid:"optional,length(5|50)" example:"1234567890"`
Industry string `json:"industry" valid:"optional,length(2|100)" example:"Technology"`
Description *string `json:"description,omitempty" valid:"optional,length(10|1000)" example:"Opplens is a technology company"`
Website *string `json:"website,omitempty" valid:"optional,url" example:"https://opplens.com"`
// Business information
EmployeeCount *int `json:"employee_count,omitempty" valid:"optional,range(1|100000)" example:"100"`
AnnualRevenue *float64 `json:"annual_revenue,omitempty" valid:"optional,range(0|999999999999)" example:"1000000"`
FoundedYear *int `json:"founded_year,omitempty" valid:"optional,range(1800|2100)" example:"2020"`
// Address information
Address *AddressForm `json:"address,omitempty"`
// Contact information
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
Email *string `json:"email,omitempty" valid:"optional,email" example:"info@opplens.com"`
DocumentFileIDs []string `json:"document_file_ids,omitempty" valid:"optional"`
Links []CompanyLinkForm `json:"links,omitempty" valid:"optional"`
// Tags for categorization and search
Tags *CompanyTagsForm `json:"tags,omitempty"`
// Settings
Language *string `json:"language,omitempty" valid:"optional,in(en|ar|fr|es|de|zh|ja|ko)" example:"en"`
Currency *string `json:"currency,omitempty" valid:"optional,in(USD|EUR|GBP|JPY|CAD|AUD|CHF|CNY|INR|BRL)" example:"USD"`
Timezone *string `json:"timezone,omitempty" valid:"optional,length(3|50)" example:"UTC"`
}
// CompanyLinkForm represents the form for a company link.
CompanyLinkForm struct {
URL string `json:"url" valid:"required,url" example:"https://example.com/profile"`
Title *string `json:"title,omitempty" valid:"optional,length(1|200)" example:"Company profile"`
}
// AddressForm represents the form for company address
AddressForm struct {
Street string `json:"street" valid:"required,length(5|200)" example:"123 Main St"`
City string `json:"city" valid:"required,length(2|100)" example:"New York"`
State string `json:"state" valid:"required,length(2|100)" example:"NY"`
PostalCode string `json:"postal_code" valid:"required,length(3|20)" example:"10001"`
Country string `json:"country" valid:"required,length(2|100)" example:"US"`
}
// CompanyTagsForm represents the form for company tags
CompanyTagsForm struct {
CPVCodes []string `json:"cpv_codes,omitempty" valid:"optional" example:"1234567890"`
Categories []string `json:"categories,omitempty" valid:"optional" example:"Technology"`
Keywords []string `json:"keywords,omitempty" valid:"optional" example:"Opplens"`
Specializations []string `json:"specializations,omitempty" valid:"optional" example:"Opplens"`
Certifications []string `json:"certifications,omitempty" valid:"optional" example:"Opplens"`
}
)
// SearchForm represents the form for searching companies with filters
type SearchForm struct {
Search *string `query:"q" valid:"optional"`
Name *string `query:"name" valid:"optional,length(1|200)"`
Email *string `query:"email" valid:"optional,length(1|254)"`
Phone *string `query:"phone" valid:"optional,length(1|20)"`
EmployeeCount *int `query:"employee_count" valid:"optional,range(1|100000)"`
Type *string `query:"type" valid:"optional,in(private|public|government|ngo|startup)"`
Status *string `query:"status" valid:"optional,in(active|inactive|suspended|pending)"`
Industry *string `query:"industry" valid:"optional"`
IsVerified *bool `query:"is_verified" valid:"optional"`
IsCompliant *bool `query:"is_compliant" valid:"optional"`
Language *string `query:"language" valid:"optional"`
Currency *string `query:"currency" valid:"optional"`
CPVCodes []string `query:"cpv_codes" valid:"optional"`
Categories []string `query:"categories" valid:"optional"`
Keywords []string `query:"keywords" valid:"optional"`
Specializations []string `query:"specializations" valid:"optional"`
EmployeeCountMin *int `query:"employee_count_min" valid:"optional,range(1|100000)"`
EmployeeCountMax *int `query:"employee_count_max" valid:"optional,range(1|100000)"`
AnnualRevenueMin *float64 `query:"annual_revenue_min" valid:"optional,min(0)"`
AnnualRevenueMax *float64 `query:"annual_revenue_max" valid:"optional,min(0)"`
FoundedYearMin *int `query:"founded_year_min" valid:"optional,range(1800|2100)"`
FoundedYearMax *int `query:"founded_year_max" valid:"optional,range(1800|2100)"`
Limit *int `query:"limit" valid:"optional,range(1|100)"`
Offset *int `query:"offset" valid:"optional,range(0|1000000)"`
SortBy *string `query:"sort_by" valid:"optional,in(name|type|industry|created_at|updated_at|status|employee_count|annual_revenue|email|phone|country|state|address.country|address.state|language|currency)"`
SortOrder *string `query:"sort_order" valid:"optional,in(asc|desc)"`
}
// StatusForm represents the form for updating company status
type StatusForm struct {
Status string `json:"status" valid:"required,in(active|inactive|suspended)"`
Reason *string `json:"reason" valid:"optional,length(10|500)"`
}
// AddLinksForm is the request body for appending links to a company.
type AddLinksForm struct {
Links []CompanyLinkForm `json:"links" valid:"required"`
}
// VerificationForm represents the form for updating company verification status
type VerificationForm struct {
IsVerified bool `json:"is_verified"`
IsCompliant bool `json:"is_compliant"`
ComplianceNotes *string `json:"compliance_notes,omitempty" valid:"optional,length(0|1000)"`
}
// CompanyListResponse represents the response for listing companies
type CompanyListResponse struct {
Companies []*CompanyResponse `json:"companies"`
Meta *response.Meta `json:"-"`
}
// CategoryResponse represents category data for company responses
type CategoryResponse struct {
ID string `json:"id"`
Name string `json:"name"`
}
// CompanyResponse represents the company data sent in API responses
type (
CompanyResponse struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Status string `json:"status"`
RegistrationNumber string `json:"registration_number"`
TaxID string `json:"tax_id"`
Industry string `json:"industry"`
Description *string `json:"description,omitempty"`
Website *string `json:"website,omitempty"`
EmployeeCount *int `json:"employee_count,omitempty"`
AnnualRevenue *float64 `json:"annual_revenue,omitempty"`
FoundedYear *int `json:"founded_year,omitempty"`
Address *Address `json:"address,omitempty"`
Phone *string `json:"phone,omitempty"`
Email *string `json:"email,omitempty"`
DocumentFileIDs []string `json:"document_file_ids,omitempty"`
Links []CompanyLink `json:"links,omitempty"`
Tags *CompanyTagsResponse `json:"tags,omitempty"`
IsVerified bool `json:"is_verified"`
IsCompliant bool `json:"is_compliant"`
ComplianceNotes *string `json:"compliance_notes,omitempty"`
Language string `json:"language"`
Currency string `json:"currency"`
Timezone string `json:"timezone"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
CompanyTagsResponse struct {
CPVCodes []string `json:"cpv_codes"`
Categories []*CategoryResponse `json:"categories"`
Keywords []string `json:"keywords"`
Specializations []string `json:"specializations"`
Certifications []string `json:"certifications"`
}
)
// ToResponse converts Company to CompanyResponse
func (c *Company) ToResponse(categories []*CategoryResponse) *CompanyResponse {
return &CompanyResponse{
ID: c.ID.Hex(),
Name: c.Name,
Type: string(c.Type),
Status: string(c.Status),
RegistrationNumber: c.RegistrationNumber,
TaxID: c.TaxID,
Industry: c.Industry,
Description: c.Description,
Website: c.Website,
EmployeeCount: c.EmployeeCount,
AnnualRevenue: c.AnnualRevenue,
FoundedYear: c.FoundedYear,
Address: c.Address,
Phone: c.Phone,
Email: c.Email,
DocumentFileIDs: c.DocumentFileIDs,
Links: c.Links,
Tags: c.Tags.ToResponse(categories),
IsVerified: c.IsVerified,
IsCompliant: c.IsCompliant,
ComplianceNotes: c.ComplianceNotes,
Language: c.Language,
Currency: c.Currency,
Timezone: c.Timezone,
CreatedAt: c.CreatedAt,
UpdatedAt: c.UpdatedAt,
}
}
func (c *CompanyTags) ToResponse(categories []*CategoryResponse) *CompanyTagsResponse {
return &CompanyTagsResponse{
CPVCodes: c.CPVCodes,
Categories: categories,
Keywords: c.Keywords,
Specializations: c.Specializations,
Certifications: c.Certifications,
}
}
// OnboardingResponse is returned after starting AI company onboarding.
type OnboardingResponse struct {
Status string `json:"status"`
}
// RecommendedTenderResponse is one ranked tender recommendation from the AI service.
type RecommendedTenderResponse struct {
Rank int `json:"rank"`
TenderID string `json:"tender_id"`
Analysis string `json:"analysis"`
}
// CompanyProfileResponse represents the company profile data sent in API responses
type CompanyProfileResponse struct {
ID string `json:"id"`
Name string `json:"name"`
RegistrationNumber string `json:"registration_number"`
Industry string `json:"industry"`
FoundedYear *int `json:"founded_year,omitempty"`
DocumentFileIDs []string `json:"document_file_ids,omitempty"`
Links []CompanyLink `json:"links,omitempty"`
CreatedAt int64 `json:"created_at"`
}
// ToResponse converts Company to CompanyResponse
func (c *Company) ToProfileResponse() *CompanyProfileResponse {
return &CompanyProfileResponse{
ID: c.ID.Hex(),
Name: c.Name,
RegistrationNumber: c.RegistrationNumber,
Industry: c.Industry,
FoundedYear: c.FoundedYear,
DocumentFileIDs: c.DocumentFileIDs,
Links: c.Links,
CreatedAt: c.CreatedAt,
}
}