224 lines
6.1 KiB
V
224 lines
6.1 KiB
V
module models
|
|
|
|
import time
|
|
|
|
// Customer represents a client or prospect in the CRM system
|
|
pub struct Customer {
|
|
BaseModel
|
|
pub mut:
|
|
name string @[required]
|
|
type CustomerType
|
|
status CustomerStatus
|
|
industry string
|
|
website string
|
|
description string
|
|
contacts []Contact
|
|
addresses []Address
|
|
projects []int // Project IDs associated with this customer
|
|
total_value f64 // Total contract value
|
|
annual_value f64 // Annual recurring revenue
|
|
payment_terms string
|
|
tax_id string
|
|
account_manager_id int // User ID of account manager
|
|
lead_source string
|
|
acquisition_date time.Time
|
|
last_contact_date time.Time
|
|
next_followup_date time.Time
|
|
credit_limit f64
|
|
payment_method string
|
|
billing_cycle string // monthly, quarterly, annually
|
|
notes string
|
|
logo_url string
|
|
social_media map[string]string // platform -> URL
|
|
custom_fields map[string]string // Flexible custom data
|
|
}
|
|
|
|
// get_primary_contact returns the primary contact for this customer
|
|
pub fn (c Customer) get_primary_contact() ?Contact {
|
|
for contact in c.contacts {
|
|
if contact.is_primary {
|
|
return contact
|
|
}
|
|
}
|
|
return none
|
|
}
|
|
|
|
// get_primary_address returns the primary address for this customer
|
|
pub fn (c Customer) get_primary_address() ?Address {
|
|
for address in c.addresses {
|
|
if address.is_primary {
|
|
return address
|
|
}
|
|
}
|
|
return none
|
|
}
|
|
|
|
// add_contact adds a new contact to the customer
|
|
pub fn (mut c Customer) add_contact(contact Contact) {
|
|
// If this is the first contact, make it primary
|
|
if c.contacts.len == 0 {
|
|
mut new_contact := contact
|
|
new_contact.is_primary = true
|
|
c.contacts << new_contact
|
|
} else {
|
|
c.contacts << contact
|
|
}
|
|
}
|
|
|
|
// update_contact updates an existing contact
|
|
pub fn (mut c Customer) update_contact(contact_id int, updated_contact Contact) bool {
|
|
for i, mut contact in c.contacts {
|
|
if contact.id == contact_id {
|
|
c.contacts[i] = updated_contact
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// remove_contact removes a contact by ID
|
|
pub fn (mut c Customer) remove_contact(contact_id int) bool {
|
|
for i, contact in c.contacts {
|
|
if contact.id == contact_id {
|
|
c.contacts.delete(i)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// add_address adds a new address to the customer
|
|
pub fn (mut c Customer) add_address(address Address) {
|
|
// If this is the first address, make it primary
|
|
if c.addresses.len == 0 {
|
|
mut new_address := address
|
|
new_address.is_primary = true
|
|
c.addresses << new_address
|
|
} else {
|
|
c.addresses << address
|
|
}
|
|
}
|
|
|
|
// update_address updates an existing address
|
|
pub fn (mut c Customer) update_address(address_id int, updated_address Address) bool {
|
|
for i, mut address in c.addresses {
|
|
if address.id == address_id {
|
|
c.addresses[i] = updated_address
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// remove_address removes an address by ID
|
|
pub fn (mut c Customer) remove_address(address_id int) bool {
|
|
for i, address in c.addresses {
|
|
if address.id == address_id {
|
|
c.addresses.delete(i)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// add_project associates a project with this customer
|
|
pub fn (mut c Customer) add_project(project_id int) {
|
|
if project_id !in c.projects {
|
|
c.projects << project_id
|
|
}
|
|
}
|
|
|
|
// remove_project removes a project association
|
|
pub fn (mut c Customer) remove_project(project_id int) {
|
|
c.projects = c.projects.filter(it != project_id)
|
|
}
|
|
|
|
// has_project checks if a project is associated with this customer
|
|
pub fn (c Customer) has_project(project_id int) bool {
|
|
return project_id in c.projects
|
|
}
|
|
|
|
// is_active_customer checks if the customer is currently active
|
|
pub fn (c Customer) is_active_customer() bool {
|
|
return c.status == .active && c.is_active
|
|
}
|
|
|
|
// is_prospect checks if the customer is still a prospect
|
|
pub fn (c Customer) is_prospect() bool {
|
|
return c.status in [.prospect, .lead, .qualified]
|
|
}
|
|
|
|
// convert_to_customer converts a prospect to an active customer
|
|
pub fn (mut c Customer) convert_to_customer(by_user_id int) {
|
|
c.status = .active
|
|
c.acquisition_date = time.now()
|
|
c.update_timestamp(by_user_id)
|
|
}
|
|
|
|
// update_last_contact updates the last contact date
|
|
pub fn (mut c Customer) update_last_contact(by_user_id int) {
|
|
c.last_contact_date = time.now()
|
|
c.update_timestamp(by_user_id)
|
|
}
|
|
|
|
// set_next_followup sets the next followup date
|
|
pub fn (mut c Customer) set_next_followup(followup_date time.Time, by_user_id int) {
|
|
c.next_followup_date = followup_date
|
|
c.update_timestamp(by_user_id)
|
|
}
|
|
|
|
// is_followup_due checks if a followup is due
|
|
pub fn (c Customer) is_followup_due() bool {
|
|
if c.next_followup_date.unix == 0 {
|
|
return false
|
|
}
|
|
return time.now() >= c.next_followup_date
|
|
}
|
|
|
|
// calculate_lifetime_value calculates the total value from all projects
|
|
pub fn (c Customer) calculate_lifetime_value(projects []Project) f64 {
|
|
mut total := f64(0)
|
|
for project in projects {
|
|
if project.customer_id == c.id {
|
|
total += project.budget
|
|
}
|
|
}
|
|
return total
|
|
}
|
|
|
|
// get_contact_by_type returns contacts of a specific type
|
|
pub fn (c Customer) get_contact_by_type(contact_type ContactType) []Contact {
|
|
return c.contacts.filter(it.type == contact_type)
|
|
}
|
|
|
|
// get_address_by_type returns addresses of a specific type
|
|
pub fn (c Customer) get_address_by_type(address_type AddressType) []Address {
|
|
return c.addresses.filter(it.type == address_type)
|
|
}
|
|
|
|
// set_account_manager assigns an account manager to this customer
|
|
pub fn (mut c Customer) set_account_manager(user_id int, by_user_id int) {
|
|
c.account_manager_id = user_id
|
|
c.update_timestamp(by_user_id)
|
|
}
|
|
|
|
// add_social_media adds a social media link
|
|
pub fn (mut c Customer) add_social_media(platform string, url string) {
|
|
c.social_media[platform] = url
|
|
}
|
|
|
|
// get_social_media gets a social media URL by platform
|
|
pub fn (c Customer) get_social_media(platform string) ?string {
|
|
return c.social_media[platform] or { none }
|
|
}
|
|
|
|
// set_custom_field sets a custom field value
|
|
pub fn (mut c Customer) set_custom_field(field string, value string) {
|
|
c.custom_fields[field] = value
|
|
}
|
|
|
|
// get_custom_field gets a custom field value
|
|
pub fn (c Customer) get_custom_field(field string) ?string {
|
|
return c.custom_fields[field] or { none }
|
|
}
|