完善供应商和客户功能

This commit is contained in:
2025-11-25 17:35:33 +08:00
parent aae2fe1e14
commit 7e4ac8fe67
20 changed files with 1524 additions and 485 deletions
+18 -1
View File
@@ -2,6 +2,7 @@ package controllers
import (
"encoding/json"
"fmt"
"strconv"
"server/models"
@@ -35,9 +36,25 @@ func (c *ContactController) List() {
// Add POST /api/crm/contact/add
func (c *ContactController) Add() {
// Debug: print the raw request body
body := string(c.Ctx.Input.RequestBody)
fmt.Printf("Received request body: %s\n", body)
// Try unmarshaling to a map first to see the raw data
var rawData map[string]interface{}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &rawData); err != nil {
fmt.Printf("JSON unmarshal error (raw): %v\n", err)
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误", "debug": body}
c.ServeJSON()
return
}
fmt.Printf("Raw data: %+v\n", rawData)
// Now try unmarshaling to the struct
var m models.Contact
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
fmt.Printf("JSON unmarshal error (struct): %v\n", err)
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误", "debug": body, "error": err.Error()}
c.ServeJSON()
return
}
+95 -61
View File
@@ -9,6 +9,7 @@ import (
"server/services"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/client/orm"
)
type CustomerController struct {
@@ -67,67 +68,67 @@ func (c *CustomerController) Add() {
// Edit POST /api/crm/customer/edit body: {id, ...}
func (c *CustomerController) Edit() {
var body map[string]interface{}
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
id, _ := body["id"].(string)
if id == "" {
// 也允许前端直接在JSON中传 id 字段,下面会再从结构体取
}
var m models.Customer
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
// 回退:从通用map中提取已知字段,避免类型不匹配导致失败
if body == nil {
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
}
toStr := func(v interface{}) string {
switch t := v.(type) {
case nil:
return ""
case string:
return t
case json.Number:
return t.String()
default:
return fmt.Sprint(v)
}
}
m = models.Customer{
Id: toStr(body["id"]),
TenantId: toStr(body["tenant_id"]),
CustomerName: toStr(body["customer_name"]),
CustomerType: toStr(body["customer_type"]),
ContactPerson: toStr(body["contact_person"]),
ContactPhone: toStr(body["contact_phone"]),
ContactEmail: toStr(body["contact_email"]),
CustomerLevel: toStr(body["customer_level"]),
Industry: toStr(body["industry"]),
Address: toStr(body["address"]),
Status: toStr(body["status"]),
Remark: toStr(body["remark"]),
}
if m.Id == "" {
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m.Id = id
}
}
if m.Id == "" {
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m.Id = id
}
if err := services.UpdateCustomer(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
var body map[string]interface{}
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
id, _ := body["id"].(string)
if id == "" {
// 也允许前端直接在JSON中传 id 字段,下面会再从结构体取
}
var m models.Customer
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
// 回退:从通用map中提取已知字段,避免类型不匹配导致失败
if body == nil {
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
}
toStr := func(v interface{}) string {
switch t := v.(type) {
case nil:
return ""
case string:
return t
case json.Number:
return t.String()
default:
return fmt.Sprint(v)
}
}
m = models.Customer{
Id: toStr(body["id"]),
TenantId: toStr(body["tenant_id"]),
CustomerName: toStr(body["customer_name"]),
CustomerType: toStr(body["customer_type"]),
ContactPerson: toStr(body["contact_person"]),
ContactPhone: toStr(body["contact_phone"]),
ContactEmail: toStr(body["contact_email"]),
CustomerLevel: toStr(body["customer_level"]),
Industry: toStr(body["industry"]),
Address: toStr(body["address"]),
Status: toStr(body["status"]),
Remark: toStr(body["remark"]),
}
if m.Id == "" {
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m.Id = id
}
}
if m.Id == "" {
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m.Id = id
}
if err := services.UpdateCustomer(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}
// Delete POST /api/crm/customer/delete body: {id, tenantId}
@@ -153,3 +154,36 @@ func (c *CustomerController) Delete() {
}
c.ServeJSON()
}
// 更新客户开票信息
func (c *CustomerController) UpdateInvoice() {
var body struct {
Id string `json:"id"`
TenantId string `json:"tenantId"`
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &body); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if body.Id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
// Extract invoice fields from the request payload
var payload map[string]interface{}
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &payload)
params := orm.Params{}
for _, key := range []string{"invoice_title", "tax_number", "bank_name", "bank_account", "registered_address", "registered_phone"} {
if v, ok := payload[key]; ok {
params[key] = v
}
}
if err := services.UpdateInvoice(body.Id, params); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}
+57 -7
View File
@@ -8,6 +8,7 @@ import (
"server/services"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/client/orm"
)
type SupplierController struct {
@@ -30,12 +31,18 @@ func (c *SupplierController) List() {
}
func (c *SupplierController) Detail() {
id := c.GetString("id")
if id == "" {
idStr := c.GetString("id")
if idStr == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
id, errConv := strconv.ParseInt(idStr, 10, 64)
if errConv != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id格式不正确"}
c.ServeJSON()
return
}
m, err := services.GetSupplier(id)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
@@ -63,20 +70,27 @@ func (c *SupplierController) Add() {
func (c *SupplierController) Edit() {
var body map[string]interface{}
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
id, _ := body["id"].(string)
var idInt int64
if v, ok := body["id"].(string); ok && v != "" {
if n, err := strconv.ParseInt(v, 10, 64); err == nil {
idInt = n
}
} else if v2, ok2 := body["id"].(float64); ok2 {
idInt = int64(v2)
}
var m models.Supplier
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if m.Id == "" {
if id == "" {
if m.Id == 0 {
if idInt == 0 {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m.Id = id
m.Id = idInt
}
if err := services.UpdateSupplier(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
@@ -101,7 +115,43 @@ func (c *SupplierController) Delete() {
c.ServeJSON()
return
}
if err := services.SoftDeleteSupplier(body.Id); err != nil {
id, errConv := strconv.ParseInt(body.Id, 10, 64)
if errConv != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id格式不正确"}
c.ServeJSON()
return
}
if err := services.SoftDeleteSupplier(id); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}
// 更新供应商开票信息
func (c *SupplierController) UpdateInvoice() {
var payload map[string]interface{}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &payload); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
idVal, ok := payload["id"]
if !ok || idVal == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
// Prepare params for service: include id and invoice fields
params := orm.Params{}
params["id"] = idVal
for _, key := range []string{"invoice_title", "tax_number", "bank_name", "bank_account", "registered_address", "registered_phone"} {
if v, exists := payload[key]; exists {
params[key] = v
}
}
if err := services.UpdateSupplierInvoice(params); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
+12
View File
@@ -593,6 +593,12 @@ CREATE TABLE `yz_tenant_crm_customer` (
`expire_time` date DEFAULT NULL COMMENT '合作到期日期(无到期则为空)',
`status` varchar(20) NOT NULL DEFAULT '1' COMMENT '客户状态(0-禁用/1-正常/2-冻结/3-已注销)',
`remark` text COMMENT '客户备注',
`invoice_title` varchar(100) DEFAULT '' COMMENT '发票抬头',
`tax_number` varchar(50) DEFAULT '' COMMENT '纳税人识别号',
`bank_name` varchar(100) DEFAULT '' COMMENT '开户行名称',
`bank_account` varchar(50) DEFAULT '' COMMENT '开户行账号',
`registered_address` varchar(255) DEFAULT '' COMMENT '注册地址',
`registered_phone` varchar(50) DEFAULT '' COMMENT '注册电话',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
@@ -627,6 +633,12 @@ CREATE TABLE `yz_tenant_crm_supplier` (
`expire_time` date DEFAULT NULL COMMENT '合作到期日期',
`status` varchar(20) NOT NULL DEFAULT '1' COMMENT '供应商状态(0-禁用/1-正常/2-冻结/3-已注销)',
`remark` text COMMENT '供应商备注',
`invoice_title` varchar(100) DEFAULT '' COMMENT '发票抬头',
`tax_number` varchar(50) DEFAULT '' COMMENT '纳税人识别号',
`bank_name` varchar(100) DEFAULT '' COMMENT '开户行名称',
`bank_account` varchar(50) DEFAULT '' COMMENT '开户行账号',
`registered_address` varchar(255) DEFAULT '' COMMENT '注册地址',
`registered_phone` varchar(50) DEFAULT '' COMMENT '注册电话',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
+22 -18
View File
@@ -8,24 +8,28 @@ import (
// Contact 联系人模型(对应表 yz_tenant_crm_contact
type Contact struct {
Id int64 `orm:"pk;auto" json:"id"`
TenantId string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
RelatedType int `orm:"column(related_type)" json:"related_type"` // 1=客户 2=供应商
RelatedId string `orm:"column(related_id);size(64)" json:"related_id"`
ContactName string `orm:"column(contact_name);size(50)" json:"contact_name"`
Gender int8 `orm:"column(gender);null" json:"gender"`
Mobile string `orm:"column(mobile);size(20);null" json:"mobile"`
Phone string `orm:"column(phone);size(20);null" json:"phone"`
Email string `orm:"column(email);size(100);null" json:"email"`
Position string `orm:"column(position);size(50);null" json:"position"`
Department string `orm:"column(department);size(50);null" json:"department"`
IsPrimary int8 `orm:"column(is_primary);null" json:"is_primary"`
Remark string `orm:"column(remark);size(500);null" json:"remark"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
CreateBy int64 `orm:"column(create_by);null" json:"create_by"`
UpdateBy int64 `orm:"column(update_by);null" json:"update_by"`
IsDeleted int8 `orm:"column(is_deleted);null" json:"is_deleted"`
Id int64 `orm:"pk;auto" json:"id,omitempty"`
TenantId string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
RelatedType int `orm:"column(related_type)" json:"related_type"` // 1=客户 2=供应商
RelatedId string `orm:"column(related_id);size(64)" json:"related_id"`
ContactName string `orm:"column(contact_name);size(50)" json:"contact_name"`
Gender int8 `orm:"column(gender);null" json:"gender"`
Phone1 string `orm:"column(phone1);size(20);null" json:"phone1"`
Phone2 string `orm:"column(phone2);size(20);null" json:"phone2"`
Phone3 string `orm:"column(phone3);size(20);null" json:"phone3"`
Qq string `orm:"column(qq);size(255);null" json:"qq"`
Wechat string `orm:"column(wechat);size(255);null" json:"wechat"`
Email string `orm:"column(email);size(100);null" json:"email"`
Position string `orm:"column(position);size(50);null" json:"position"`
Department string `orm:"column(department);size(50);null" json:"department"`
IsPrimary int8 `orm:"column(is_primary);null" json:"is_primary"`
HomeAddress string `orm:"column(home_address);size(65535);null" json:"home_address"`
Remark string `orm:"column(remark);size(65535);null" json:"remark"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time,omitempty"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time,omitempty"`
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time,omitempty"`
CreateBy int64 `orm:"column(create_by);null" json:"create_by"`
UpdateBy int64 `orm:"column(update_by);null" json:"update_by"`
}
func (t *Contact) TableName() string {
+6
View File
@@ -22,6 +22,12 @@ type Customer struct {
ExpireTime *time.Time `orm:"column(expire_time);null;type(date)" json:"expire_time"`
Status string `orm:"column(status);size(20)" json:"status"`
Remark string `orm:"column(remark);type(text);null" json:"remark"`
InvoiceTitle string `orm:"column(invoice_title);size(100);null" json:"invoice_title"`
TaxNumber string `orm:"column(tax_number);size(50);null" json:"tax_number"`
BankName string `orm:"column(bank_name);size(100);null" json:"bank_name"`
BankAccount string `orm:"column(bank_account);size(50);null" json:"bank_account"`
RegisteredAddress string `orm:"column(registered_address);size(255);null" json:"registered_address"`
RegisteredPhone string `orm:"column(registered_phone);size(50);null" json:"registered_phone"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time"`
+24 -18
View File
@@ -8,23 +8,29 @@ import (
// Supplier 供应商模型(对应表 yz_tenant_crm_supplier
type Supplier struct {
Id string `orm:"pk;size(36)" json:"id"`
TenantId string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
SupplierName string `orm:"column(supplier_name);size(100)" json:"supplier_name"`
SupplierType string `orm:"column(supplier_type);size(20)" json:"supplier_type"`
ContactPerson string `orm:"column(contact_person);size(50)" json:"contact_person"`
ContactPhone string `orm:"column(contact_phone);size(20)" json:"contact_phone"`
ContactEmail string `orm:"column(contact_email);size(100);null" json:"contact_email"`
SupplierLevel string `orm:"column(supplier_level);size(20);null" json:"supplier_level"`
Industry string `orm:"column(industry);size(50);null" json:"industry"`
Address string `orm:"column(address);size(255);null" json:"address"`
RegisterTime *time.Time `orm:"column(register_time);null;type(date)" json:"register_time"`
ExpireTime *time.Time `orm:"column(expire_time);null;type(date)" json:"expire_time"`
Status string `orm:"column(status);size(20)" json:"status"`
Remark string `orm:"column(remark);type(text);null" json:"remark"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time"`
Id int64 `orm:"pk;auto" json:"id"`
TenantId string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
SupplierName string `orm:"column(supplier_name);size(100)" json:"supplier_name"`
SupplierType string `orm:"column(supplier_type);size(20)" json:"supplier_type"`
ContactPerson string `orm:"column(contact_person);size(50)" json:"contact_person"`
ContactPhone string `orm:"column(contact_phone);size(20)" json:"contact_phone"`
ContactEmail string `orm:"column(contact_email);size(100);null" json:"contact_email"`
SupplierLevel string `orm:"column(supplier_level);size(20);null" json:"supplier_level"`
Industry string `orm:"column(industry);size(50);null" json:"industry"`
Address string `orm:"column(address);size(255);null" json:"address"`
RegisterTime *time.Time `orm:"column(register_time);null;type(date)" json:"register_time"`
ExpireTime *time.Time `orm:"column(expire_time);null;type(date)" json:"expire_time"`
Status string `orm:"column(status);size(20)" json:"status"`
Remark string `orm:"column(remark);type(text);null" json:"remark"`
InvoiceTitle string `orm:"column(invoice_title);size(255);null" json:"invoice_title"`
TaxNumber string `orm:"column(tax_number);size(20);null" json:"tax_number"`
BankName string `orm:"column(bank_name);size(50);null" json:"bank_name"`
BankAccount string `orm:"column(bank_account);size(50);null" json:"bank_account"`
RegisteredAddress string `orm:"column(registered_address);size(255);null" json:"registered_address"`
RegisteredPhone string `orm:"column(registered_phone);size(20);null" json:"registered_phone"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time"`
}
func (t *Supplier) TableName() string {
@@ -33,4 +39,4 @@ func (t *Supplier) TableName() string {
func init() {
orm.RegisterModel(new(Supplier))
}
}
+2
View File
@@ -335,6 +335,7 @@ func init() {
beego.Router("/api/crm/customer/add", &controllers.CustomerController{}, "post:Add")
beego.Router("/api/crm/customer/edit", &controllers.CustomerController{}, "post:Edit")
beego.Router("/api/crm/customer/delete", &controllers.CustomerController{}, "post:Delete")
beego.Router("/api/crm/customer/update-invoice", &controllers.CustomerController{}, "post:UpdateInvoice")
// CRM 供应商路由
beego.Router("/api/crm/supplier/list", &controllers.SupplierController{}, "get:List")
@@ -342,6 +343,7 @@ func init() {
beego.Router("/api/crm/supplier/add", &controllers.SupplierController{}, "post:Add")
beego.Router("/api/crm/supplier/edit", &controllers.SupplierController{}, "post:Edit")
beego.Router("/api/crm/supplier/delete", &controllers.SupplierController{}, "post:Delete")
beego.Router("/api/crm/supplier/update-invoice", &controllers.SupplierController{}, "post:UpdateInvoice")
// CRM 联系人路由
beego.Router("/api/crm/contact/list", &controllers.ContactController{}, "get:List")
+20 -17
View File
@@ -2,15 +2,17 @@ package services
import (
"errors"
"time"
"server/models"
"github.com/beego/beego/v2/client/orm"
"server/models"
)
func ListContacts(tenantId string, relatedType int, relatedId string) ([]models.Contact, error) {
o := orm.NewOrm()
var list []models.Contact
qs := o.QueryTable(new(models.Contact)).Filter("tenant_id", tenantId).Filter("related_type", relatedType).Filter("related_id", relatedId).Filter("is_deleted", 0)
qs := o.QueryTable(new(models.Contact)).Filter("tenant_id", tenantId).Filter("related_type", relatedType).Filter("related_id", relatedId).Filter("delete_time__isnull", true)
_, err := qs.All(&list)
return list, err
}
@@ -20,10 +22,6 @@ func CreateContact(m *models.Contact) error {
return errors.New("缺少必填参数")
}
o := orm.NewOrm()
// 若设为主联系人,则先清理同归属其他主联系人
if m.IsPrimary == 1 {
_, _ = o.QueryTable(new(models.Contact)).Filter("tenant_id", m.TenantId).Filter("related_type", m.RelatedType).Filter("related_id", m.RelatedId).Filter("is_deleted", 0).Update(orm.Params{"is_primary": 0})
}
_, err := o.Insert(m)
return err
}
@@ -33,16 +31,17 @@ func UpdateContact(m *models.Contact) error {
return errors.New("id不能为空")
}
o := orm.NewOrm()
// 若设为主联系人,则先清理同归属其他主联系人
if m.IsPrimary == 1 {
// 需要获取原始记录以得到 tenant/related
var origin models.Contact
origin.Id = m.Id
if err := o.Read(&origin); err == nil {
_, _ = o.QueryTable(new(models.Contact)).Filter("tenant_id", origin.TenantId).Filter("related_type", origin.RelatedType).Filter("related_id", origin.RelatedId).Filter("id__ne", m.Id).Filter("is_deleted", 0).Update(orm.Params{"is_primary": 0})
}
existing := models.Contact{Id: m.Id}
if err := o.Read(&existing); err != nil {
return err
}
_, err := o.Update(m, "contact_name", "gender", "mobile", "phone", "email", "position", "department", "is_primary", "remark")
if existing.TenantId != m.TenantId {
return errors.New("租户不匹配")
}
if existing.DeleteTime != nil {
return errors.New("记录已删除")
}
_, err := o.Update(m, "contact_name", "gender", "phone1", "phone2", "phone3", "qq", "wechat", "email", "position", "department", "home_address", "remark", "is_primary")
return err
}
@@ -58,7 +57,11 @@ func DeleteContact(id int64, tenantId string) error {
if m.TenantId != tenantId {
return errors.New("租户不匹配")
}
m.IsDeleted = 1
_, err := o.Update(&m, "is_primary", "is_deleted")
if m.DeleteTime != nil {
return errors.New("记录已删除")
}
now := time.Now()
m.DeleteTime = &now
_, err := o.Update(&m, "delete_time")
return err
}
+62 -52
View File
@@ -1,79 +1,89 @@
package services
import (
"time"
"time"
"server/models"
"server/models"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/client/orm"
)
// ListCustomers 获取客户列表(可选租户过滤、关键词搜索、状态筛选、分页)
func ListCustomers(tenantId, keyword, status string, page, pageSize int) (list []*models.Customer, total int64, err error) {
o := orm.NewOrm()
qs := o.QueryTable(new(models.Customer)).Filter("delete_time__isnull", true)
if tenantId != "" {
qs = qs.Filter("tenant_id", tenantId)
}
if keyword != "" {
cond := orm.NewCondition()
cond1 := cond.Or("customer_name__icontains", keyword).
Or("contact_person__icontains", keyword).
Or("contact_phone__icontains", keyword)
qs = qs.SetCond(cond1)
}
if status != "" {
qs = qs.Filter("status", status)
}
o := orm.NewOrm()
qs := o.QueryTable(new(models.Customer)).Filter("delete_time__isnull", true)
if tenantId != "" {
qs = qs.Filter("tenant_id", tenantId)
}
if keyword != "" {
cond := orm.NewCondition()
cond1 := cond.Or("customer_name__icontains", keyword).
Or("contact_person__icontains", keyword).
Or("contact_phone__icontains", keyword)
qs = qs.SetCond(cond1)
}
if status != "" {
qs = qs.Filter("status", status)
}
total, err = qs.Count()
if err != nil {
return
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
offset := (page - 1) * pageSize
_, err = qs.OrderBy("-create_time").Limit(pageSize, offset).All(&list)
return
total, err = qs.Count()
if err != nil {
return
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
offset := (page - 1) * pageSize
_, err = qs.OrderBy("-create_time").Limit(pageSize, offset).All(&list)
return
}
// GetCustomer 通过ID获取客户
func GetCustomer(id string) (*models.Customer, error) {
o := orm.NewOrm()
m := models.Customer{Id: id}
if err := o.Read(&m); err != nil {
return nil, err
}
return &m, nil
o := orm.NewOrm()
m := models.Customer{Id: id}
if err := o.Read(&m); err != nil {
return nil, err
}
return &m, nil
}
// CreateCustomer 新增客户
func CreateCustomer(m *models.Customer) error {
o := orm.NewOrm()
_, err := o.Insert(m)
return err
o := orm.NewOrm()
_, err := o.Insert(m)
return err
}
// UpdateCustomer 更新客户(全量更新)
func UpdateCustomer(m *models.Customer, cols ...string) error {
o := orm.NewOrm()
if len(cols) == 0 {
_, err := o.Update(m)
return err
}
_, err := o.Update(m, cols...)
return err
o := orm.NewOrm()
if len(cols) == 0 {
_, err := o.Update(m)
return err
}
_, err := o.Update(m, cols...)
return err
}
// SoftDeleteCustomer 软删除客户
func SoftDeleteCustomer(id string) error {
o := orm.NewOrm()
now := time.Now()
m := models.Customer{Id: id, DeleteTime: &now}
_, err := o.Update(&m, "delete_time")
return err
o := orm.NewOrm()
now := time.Now()
m := models.Customer{Id: id, DeleteTime: &now}
_, err := o.Update(&m, "delete_time")
return err
}
// 更新客户开票信息
func UpdateInvoice(id string, params orm.Params) error {
o := orm.NewOrm()
m := &models.Customer{Id: id}
if _, err := o.QueryTable(m).Filter("id", id).Update(params); err != nil {
return err
}
return nil
}
+91 -54
View File
@@ -1,79 +1,116 @@
package services
import (
"time"
"fmt"
"strconv"
"time"
"server/models"
"server/models"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/client/orm"
)
// ListSuppliers 获取供应商列表(可选租户过滤、关键词搜索、状态筛选、分页)
func ListSuppliers(tenantId, keyword, status string, page, pageSize int) (list []*models.Supplier, total int64, err error) {
o := orm.NewOrm()
qs := o.QueryTable(new(models.Supplier)).Filter("delete_time__isnull", true)
if tenantId != "" {
qs = qs.Filter("tenant_id", tenantId)
}
if keyword != "" {
cond := orm.NewCondition()
cond1 := cond.Or("supplier_name__icontains", keyword).
Or("contact_person__icontains", keyword).
Or("contact_phone__icontains", keyword)
qs = qs.SetCond(cond1)
}
if status != "" {
qs = qs.Filter("status", status)
}
o := orm.NewOrm()
qs := o.QueryTable(new(models.Supplier)).Filter("delete_time__isnull", true)
if tenantId != "" {
qs = qs.Filter("tenant_id", tenantId)
}
if keyword != "" {
cond := orm.NewCondition()
cond1 := cond.Or("supplier_name__icontains", keyword).
Or("contact_person__icontains", keyword).
Or("contact_phone__icontains", keyword)
qs = qs.SetCond(cond1)
}
if status != "" {
qs = qs.Filter("status", status)
}
total, err = qs.Count()
if err != nil {
return
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
offset := (page - 1) * pageSize
_, err = qs.OrderBy("-create_time").Limit(pageSize, offset).All(&list)
return
total, err = qs.Count()
if err != nil {
return
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
offset := (page - 1) * pageSize
_, err = qs.OrderBy("-create_time").Limit(pageSize, offset).All(&list)
return
}
// GetSupplier 通过ID获取供应商
func GetSupplier(id string) (*models.Supplier, error) {
o := orm.NewOrm()
m := models.Supplier{Id: id}
if err := o.Read(&m); err != nil {
return nil, err
}
return &m, nil
func GetSupplier(id int64) (*models.Supplier, error) {
o := orm.NewOrm()
m := models.Supplier{Id: id}
if err := o.Read(&m); err != nil {
return nil, err
}
return &m, nil
}
// CreateSupplier 新增供应商
func CreateSupplier(m *models.Supplier) error {
o := orm.NewOrm()
_, err := o.Insert(m)
return err
o := orm.NewOrm()
_, err := o.Insert(m)
return err
}
// UpdateSupplier 更新供应商(全量更新)
func UpdateSupplier(m *models.Supplier, cols ...string) error {
o := orm.NewOrm()
if len(cols) == 0 {
_, err := o.Update(m)
return err
}
_, err := o.Update(m, cols...)
return err
o := orm.NewOrm()
if len(cols) == 0 {
_, err := o.Update(m)
return err
}
_, err := o.Update(m, cols...)
return err
}
// SoftDeleteSupplier 软删除供应商
func SoftDeleteSupplier(id string) error {
o := orm.NewOrm()
now := time.Now()
m := models.Supplier{Id: id, DeleteTime: &now}
_, err := o.Update(&m, "delete_time")
return err
func SoftDeleteSupplier(id int64) error {
o := orm.NewOrm()
now := time.Now()
m := models.Supplier{Id: id, DeleteTime: &now}
_, err := o.Update(&m, "delete_time")
return err
}
// 更新供应商开票信息
func UpdateSupplierInvoice(params orm.Params) error {
o := orm.NewOrm()
// Extract id from params
idVal, ok := params["id"]
if !ok || idVal == "" {
return fmt.Errorf("id is required")
}
var id int64
switch v := idVal.(type) {
case int64:
id = v
case int:
id = int64(v)
case float64:
id = int64(v)
case string:
if v == "" {
return fmt.Errorf("id is required")
}
n, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return fmt.Errorf("invalid id: %v", err)
}
id = n
default:
return fmt.Errorf("invalid id type")
}
delete(params, "id") // remove id from update fields
if _, err := o.QueryTable(new(models.Supplier)).Filter("id", id).Update(params); err != nil {
return err
}
return nil
}