|
@@ -0,0 +1,291 @@
|
|
|
|
|
+package repo
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "database/sql"
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "saura/src/common"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+const (
|
|
|
|
|
+ ClientTypePhysical string = "Физ"
|
|
|
|
|
+ ClientTypeLegal string = "Юр"
|
|
|
|
|
+ ClientTypeSupplier string = "Поставщик"
|
|
|
|
|
+ ClientTypeEmployee string = "Сотрудник"
|
|
|
|
|
+ ClientTypeCounterparty string = "Контрагент"
|
|
|
|
|
+ ClientTypeCustomer string = "Покупатель"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+type ClientInfo struct {
|
|
|
|
|
+ Id string `db:"id" json:"id" form:"id"`
|
|
|
|
|
+ Id2 string `db:"id2" json:"id2" form:"id2"`
|
|
|
|
|
+ Mark string `db:"mark" json:"mark" form:"mark"`
|
|
|
|
|
+ Contractor bool `db:"contractor" json:"contractor" form:"contractor"`
|
|
|
|
|
+ FullName string `db:"full_name" json:"full_name" form:"full_name"`
|
|
|
|
|
+ Type string `db:"type" json:"type" form:"type"`
|
|
|
|
|
+ Phones []string `json:"phones" form:"phones"`
|
|
|
|
|
+ Email string `db:"email" json:"email" form:"email"`
|
|
|
|
|
+ LegalAddress string `db:"legal_address" json:"legal_address" form:"legal_address"`
|
|
|
|
|
+ PhysicalAddress string `db:"physical_address" json:"physical_address" form:"physical_address"`
|
|
|
|
|
+ RegistrationDate string `db:"registration_date" json:"registration_date" form:"registration_date"`
|
|
|
|
|
+ AdChannel string `db:"ad_channel" json:"ad_channel" form:"ad_channel"`
|
|
|
|
|
+ RegData1 string `db:"reg_data_1" json:"reg_data_1" form:"reg_data_1"`
|
|
|
|
|
+ RegData2 string `db:"reg_data_2" json:"reg_data_2" form:"reg_data_2"`
|
|
|
|
|
+ Note string `db:"note" json:"note" form:"note"`
|
|
|
|
|
+ RequestCount int `db:"request_count" json:"request_count" form:"request_count"`
|
|
|
|
|
+ Birthday string `db:"birthday" json:"birthday" form:"birthday"`
|
|
|
|
|
+ Income common.Money `db:"income" json:"income" form:"income"`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type ClientRepo struct {
|
|
|
|
|
+ db *sql.DB
|
|
|
|
|
+ dbUrl string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func NewClientRepo(db *sql.DB, dbUrl string) *ClientRepo {
|
|
|
|
|
+ return &ClientRepo{db: db, dbUrl: dbUrl}
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (r *ClientRepo) InsertClient(client ClientInfo) error {
|
|
|
|
|
+ var err error
|
|
|
|
|
+ var exists bool
|
|
|
|
|
+
|
|
|
|
|
+ err = r.db.QueryRow("SELECT EXISTS(SELECT 1 FROM clients WHERE id = ? OR id2 = ?)", client.Id, client.Id2).Scan(&exists)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to check if client exists: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if exists {
|
|
|
|
|
+ return fmt.Errorf("client with id %s already exists", client.Id)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _, err = r.db.Exec(
|
|
|
|
|
+ `
|
|
|
|
|
+ INSERT INTO clients (
|
|
|
|
|
+ id, id2, mark, contractor, full_name, type, email,
|
|
|
|
|
+ legal_address, physical_address, registration_date, ad_channel,
|
|
|
|
|
+ reg_data_1, reg_data_2, note, request_count, birthday, income
|
|
|
|
|
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
|
|
+ `,
|
|
|
|
|
+ client.Id, client.Id2, client.Mark, client.Contractor, client.FullName,
|
|
|
|
|
+ client.Type, client.Email, client.LegalAddress,
|
|
|
|
|
+ client.PhysicalAddress, client.RegistrationDate, client.AdChannel,
|
|
|
|
|
+ client.RegData1, client.RegData2, client.Note, client.RequestCount,
|
|
|
|
|
+ client.Birthday, client.Income,
|
|
|
|
|
+ )
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to insert client: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (r *ClientRepo) FetchClientByID(id string) (*ClientInfo, error) {
|
|
|
|
|
+ var err error
|
|
|
|
|
+
|
|
|
|
|
+ row := r.db.QueryRow(`
|
|
|
|
|
+ SELECT
|
|
|
|
|
+ id, id2, mark, contractor, full_name, type, email,
|
|
|
|
|
+ legal_address, physical_address, registration_date, ad_channel,
|
|
|
|
|
+ reg_data_1, reg_data_2, note, request_count, birthday, income
|
|
|
|
|
+ FROM clients
|
|
|
|
|
+ WHERE id = ?
|
|
|
|
|
+ `, id)
|
|
|
|
|
+
|
|
|
|
|
+ var client ClientInfo
|
|
|
|
|
+ err = row.Scan(
|
|
|
|
|
+ &client.Id, &client.Id2, &client.Mark, &client.Contractor, &client.FullName,
|
|
|
|
|
+ &client.Type, &client.Email, &client.LegalAddress,
|
|
|
|
|
+ &client.PhysicalAddress, &client.RegistrationDate, &client.AdChannel,
|
|
|
|
|
+ &client.RegData1, &client.RegData2, &client.Note, &client.RequestCount,
|
|
|
|
|
+ &client.Birthday, &client.Income,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ if err == sql.ErrNoRows {
|
|
|
|
|
+ return nil, fmt.Errorf("client with id %s not found", id)
|
|
|
|
|
+ } else if err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("failed to scan row: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ phones, err := r.FetchClientPhones(client.Id)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("error: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ client.Phones = phones
|
|
|
|
|
+
|
|
|
|
|
+ return &client, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (r *ClientRepo) InsertClientPhones(client_id string, phones []string) error {
|
|
|
|
|
+ for _, phone := range phones {
|
|
|
|
|
+ _, err := r.db.Exec("INSERT INTO client_phones VALUES(?, ?)", client_id, phone)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (r *ClientRepo) FetchClientPhones(client_id string) ([]string, error) {
|
|
|
|
|
+ rows, err := r.db.Query("SELECT phone FROM client_phones WHERE client_id = ?", client_id)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ defer rows.Close()
|
|
|
|
|
+
|
|
|
|
|
+ var tags []string
|
|
|
|
|
+ for rows.Next() {
|
|
|
|
|
+ var tag string
|
|
|
|
|
+ rows.Scan(&tag)
|
|
|
|
|
+ tags = append(tags, tag)
|
|
|
|
|
+ }
|
|
|
|
|
+ return tags, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (r *ClientRepo) FetchClients(count int, offset int) ([]ClientInfo, error) {
|
|
|
|
|
+ rows, err := r.db.Query(`
|
|
|
|
|
+ SELECT
|
|
|
|
|
+ id, id2, mark, contractor, full_name, type, email,
|
|
|
|
|
+ legal_address, physical_address, registration_date, ad_channel,
|
|
|
|
|
+ reg_data_1, reg_data_2, note, request_count, birthday, income
|
|
|
|
|
+ FROM clients
|
|
|
|
|
+ LIMIT ? OFFSET ?
|
|
|
|
|
+ `, count, offset)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("failed to execute query: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ defer rows.Close()
|
|
|
|
|
+
|
|
|
|
|
+ var clients []ClientInfo
|
|
|
|
|
+ for rows.Next() {
|
|
|
|
|
+ var client ClientInfo
|
|
|
|
|
+ err := rows.Scan(
|
|
|
|
|
+ &client.Id,
|
|
|
|
|
+ &client.Id2,
|
|
|
|
|
+ &client.Mark,
|
|
|
|
|
+ &client.Contractor,
|
|
|
|
|
+ &client.FullName,
|
|
|
|
|
+ &client.Type,
|
|
|
|
|
+ &client.Email,
|
|
|
|
|
+ &client.LegalAddress,
|
|
|
|
|
+ &client.PhysicalAddress,
|
|
|
|
|
+ &client.RegistrationDate, // time.Time или sql.NullTime
|
|
|
|
|
+ &client.AdChannel,
|
|
|
|
|
+ &client.RegData1,
|
|
|
|
|
+ &client.RegData2,
|
|
|
|
|
+ &client.Note, // sql.NullString
|
|
|
|
|
+ &client.RequestCount, // int или sql.NullInt32
|
|
|
|
|
+ &client.Birthday, // time.Time или sql.NullTime
|
|
|
|
|
+ &client.Income, // float64 или sql.NullFloat64
|
|
|
|
|
+ )
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("failed to scan row: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ phones, err := r.FetchClientPhones(client.Id)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("rows error: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ client.Phones = phones
|
|
|
|
|
+
|
|
|
|
|
+ clients = append(clients, client)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Проверка ошибок после итерации
|
|
|
|
|
+ if err := rows.Err(); err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("rows error: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return clients, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (r *ClientRepo) FetchClientsCount() (int, error) {
|
|
|
|
|
+ var count int
|
|
|
|
|
+ query := "SELECT COUNT(*) FROM clients"
|
|
|
|
|
+ err := r.db.QueryRow(query).Scan(&count)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return 0, fmt.Errorf("failed to fetch count: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return count, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (r *ClientRepo) DeleteClient(id string) error {
|
|
|
|
|
+ query := "DELETE FROM clients WHERE id = ?"
|
|
|
|
|
+ result, err := r.db.Exec(query, id)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to delete client: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ rowsAffected, err := result.RowsAffected()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to get rows affected: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if rowsAffected == 0 {
|
|
|
|
|
+ return fmt.Errorf("client with id %s not found", id)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (r *ClientRepo) UpdateClient(id string, client ClientInfo) error {
|
|
|
|
|
+ // Проверим, существует ли клиент
|
|
|
|
|
+ var exists string
|
|
|
|
|
+ err := r.db.QueryRow("SELECT id FROM clients WHERE id = ?", id).Scan(&exists)
|
|
|
|
|
+ if err == sql.ErrNoRows {
|
|
|
|
|
+ return fmt.Errorf("client with id %s not found", id)
|
|
|
|
|
+ } else if err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to check client existence: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ query := `
|
|
|
|
|
+ UPDATE clients SET
|
|
|
|
|
+ id = ?,
|
|
|
|
|
+ id2 = ?,
|
|
|
|
|
+ mark = ?,
|
|
|
|
|
+ contractor = ?,
|
|
|
|
|
+ full_name = ?,
|
|
|
|
|
+ type = ?,
|
|
|
|
|
+ email = ?,
|
|
|
|
|
+ legal_address = ?,
|
|
|
|
|
+ physical_address = ?,
|
|
|
|
|
+ registration_date = ?,
|
|
|
|
|
+ ad_channel = ?,
|
|
|
|
|
+ reg_data_1 = ?,
|
|
|
|
|
+ reg_data_2 = ?,
|
|
|
|
|
+ note = ?,
|
|
|
|
|
+ request_count = ?,
|
|
|
|
|
+ birthday = ?,
|
|
|
|
|
+ income = ?
|
|
|
|
|
+ WHERE id = ?
|
|
|
|
|
+ `
|
|
|
|
|
+
|
|
|
|
|
+ contractorInt := 0
|
|
|
|
|
+ if client.Contractor {
|
|
|
|
|
+ contractorInt = 1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _, err = r.db.Exec(query,
|
|
|
|
|
+ id,
|
|
|
|
|
+ client.Id2,
|
|
|
|
|
+ client.Mark,
|
|
|
|
|
+ contractorInt,
|
|
|
|
|
+ client.FullName,
|
|
|
|
|
+ client.Type,
|
|
|
|
|
+ client.Email,
|
|
|
|
|
+ client.LegalAddress,
|
|
|
|
|
+ client.PhysicalAddress,
|
|
|
|
|
+ client.RegistrationDate,
|
|
|
|
|
+ client.AdChannel,
|
|
|
|
|
+ client.RegData1,
|
|
|
|
|
+ client.RegData2,
|
|
|
|
|
+ client.Note,
|
|
|
|
|
+ client.RequestCount,
|
|
|
|
|
+ client.Birthday,
|
|
|
|
|
+ client.Income,
|
|
|
|
|
+ id,
|
|
|
|
|
+ )
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to update client: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|