批量更新功能
This commit is contained in:
@@ -12,7 +12,9 @@ type BackendErpContact struct {
|
||||
ContactType int8 `orm:"column(contact_type);default(1)" json:"contact_type"`
|
||||
ContactName string `orm:"column(contact_name);size(64)" json:"contact_name"`
|
||||
Gender int8 `orm:"column(gender);default(0)" json:"gender"`
|
||||
Phone *string `orm:"column(phone);size(20);null" json:"phone"`
|
||||
Phone *string `orm:"column(phone);size(20);null" json:"phone"` // 手机号(保留第一个,兼容旧逻辑)
|
||||
// 手机号可登记多个(有的人有多个号码):JSON 数组,最多 5 个,phone 始终与其中一个(第一个)保持一致
|
||||
Mobiles *string `orm:"column(mobiles);type(text);null" json:"mobiles"`
|
||||
WorkPhone *string `orm:"column(work_phone);size(20);null" json:"work_phone"`
|
||||
Email *string `orm:"column(email);size(128);null" json:"email"`
|
||||
Wechat *string `orm:"column(wechat);size(64);null" json:"wechat"`
|
||||
|
||||
+20
-5
@@ -156,6 +156,7 @@ func Init(_ string) {
|
||||
EnsureCrmPaybackRecordTable()
|
||||
EnsureCrmProductDevColumns()
|
||||
EnsureCrmUnitTable()
|
||||
EnsureErpCompanyContactMobilesColumn()
|
||||
}
|
||||
|
||||
// EnsureCrmPaybackTable 回款计划表建表(CREATE TABLE IF NOT EXISTS,可重复执行;
|
||||
@@ -278,7 +279,7 @@ func EnsureCrmContractTable() {
|
||||
total_amount decimal(14,2) NOT NULL DEFAULT '0.00' COMMENT '合同总金额',
|
||||
total_cost decimal(14,2) NOT NULL DEFAULT '0.00' COMMENT '产品总成本',
|
||||
total_profit decimal(14,2) NOT NULL DEFAULT '0.00' COMMENT '合同总利润',
|
||||
status tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1草稿/2已完成/3已作废/4履约中/5执行异常',
|
||||
status tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1草稿/2已完成/3已作废/4履约中/5异常',
|
||||
step tinyint(4) NOT NULL DEFAULT '1' COMMENT '进度步骤:1合同信息/2产品清单',
|
||||
remark text COMMENT '备注',
|
||||
create_user_id varchar(64) NOT NULL DEFAULT '' COMMENT '创建人用户ID',
|
||||
@@ -335,13 +336,30 @@ func EnsureCrmUnitTable() {
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureCrmProductDevColumns 补齐产品表的软件开发字段(line_type / dev_unit_price / dev_tree);
|
||||
// EnsureErpCompanyContactMobilesColumn 补齐公司联系人表(yz_backend_contact_company)的多手机号字段 mobiles。
|
||||
// 该表为客户/供应商正式联系人的共用库(项目联系人选择、通讯录、客户-供应商转化等均读取),
|
||||
// 早期多手机号升级遗漏了此表,缺列会导致查询报错(前端表现为「联系人不显示」)。
|
||||
// 表不存在或列已存在时忽略错误,可用 docs/sql/alter_contact_mobiles.sql 手动修复。
|
||||
func EnsureErpCompanyContactMobilesColumn() {
|
||||
table := new(ErpCompanyContact).TableName()
|
||||
sql := fmt.Sprintf("ALTER TABLE %s ADD COLUMN mobiles text NULL COMMENT '手机号 JSON 数组(最多5个),phone 保留座机语义'", table)
|
||||
if _, err := Orm.Raw(sql).Exec(); err != nil {
|
||||
// 列已存在或表不存在时忽略
|
||||
return
|
||||
}
|
||||
// 历史数据回填:原 phone 中的号码作为第一个手机号(仅在 mobiles 为空时)
|
||||
_, _ = Orm.Raw("UPDATE " + table +
|
||||
" SET mobiles = JSON_ARRAY(phone) WHERE (mobiles IS NULL OR mobiles = '') AND phone IS NOT NULL AND phone <> ''").Exec()
|
||||
}
|
||||
|
||||
// EnsureCrmProductDevColumns 补齐产品表的软件开发字段(line_type / dev_unit_price / dev_mode / dev_tree);
|
||||
// 表不存在或列已存在时忽略错误,可用 docs/sql/alter_backend_crm_product_dev_columns.sql 手动修复。
|
||||
func EnsureCrmProductDevColumns() {
|
||||
table := new(TenantCrmProduct).TableName()
|
||||
cols := []string{
|
||||
"line_type varchar(20) NOT NULL DEFAULT 'product' COMMENT '行类型:product成品/dev软件开发'",
|
||||
"dev_unit_price decimal(14,2) NOT NULL DEFAULT '0.00' COMMENT '软件开发统一人天单价'",
|
||||
"dev_mode varchar(20) NOT NULL DEFAULT 'self' COMMENT '软件开发研发方式:self自行研发/outsource外协研发'",
|
||||
"dev_tree text COMMENT '软件开发模块树JSON(叶子人天×统一人天单价)'",
|
||||
}
|
||||
for _, col := range cols {
|
||||
@@ -353,9 +371,6 @@ func EnsureCrmProductDevColumns() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// EnsureCrmCreateUserColumn 补齐客户/供应商的创建人字段(用于删除权限校验)。
|
||||
// 同样兼容历史表名差异,表不存在或列已存在时忽略错误。
|
||||
func EnsureCrmCreateUserColumn() {
|
||||
|
||||
@@ -22,7 +22,7 @@ type TenantCrmClue struct {
|
||||
ContactWechat string `orm:"column(contact_wechat);size(64)" json:"contact_wechat"` // 对接人微信
|
||||
ContactQQ string `orm:"column(contact_qq);size(20)" json:"contact_qq"` // 对接人QQ
|
||||
Address string `orm:"column(address);size(255)" json:"address"` // 公司地址
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1跟进中/2已转化/3已关闭
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1跟进中/2已转化/3已废弃
|
||||
Locked int8 `orm:"column(locked);default(0)" json:"locked"` // 0否/1是(转化后锁定不可编辑)
|
||||
BusinessID *uint64 `orm:"column(business_id);null" json:"business_id"` // 转化后的商机ID
|
||||
ConvertTime *time.Time `orm:"column(convert_time);type(datetime);null" json:"convert_time"` // 转化时间
|
||||
|
||||
@@ -13,8 +13,8 @@ import "time"
|
||||
type TenantCrmContract struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
|
||||
ContractNo string `orm:"column(contract_no);size(50)" json:"contract_no"` // 合同编号
|
||||
ContractName string `orm:"column(contract_name);size(100)" json:"contract_name"` // 合同名称
|
||||
ContractNo string `orm:"column(contract_no);size(50)" json:"contract_no"` // 合同编号
|
||||
ContractName string `orm:"column(contract_name);size(100)" json:"contract_name"` // 合同名称
|
||||
ContractCategory string `orm:"column(contract_category);size(20)" json:"contract_category"` // 分类:1开发/2服务/3销售/4租赁/5采购/6运维/7咨询/8其他
|
||||
OurRole int8 `orm:"column(our_role);default(2)" json:"our_role"` // 我方角色:1甲方/2乙方/3丙方/4丁方
|
||||
PartyCount int8 `orm:"column(party_count);default(2)" json:"party_count"` // 合同形式:2/3/4 方
|
||||
@@ -33,7 +33,7 @@ type TenantCrmContract struct {
|
||||
TotalAmount float64 `orm:"column(total_amount);digits(14);decimals(2);default(0)" json:"total_amount"`
|
||||
TotalCost float64 `orm:"column(total_cost);digits(14);decimals(2);default(0)" json:"total_cost"`
|
||||
TotalProfit float64 `orm:"column(total_profit);digits(14);decimals(2);default(0)" json:"total_profit"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1草稿/2已完成/3已作废/4履约中/5执行异常
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1草稿/2已完成/3已作废/4履约中/5异常
|
||||
Step int8 `orm:"column(step);default(1)" json:"step"` // 进度式创建步骤:1合同信息/2产品清单
|
||||
Remark string `orm:"column(remark);type(text);null" json:"remark"`
|
||||
CreateUserID string `orm:"column(create_user_id);size(64)" json:"create_user_id"`
|
||||
|
||||
@@ -11,7 +11,9 @@ type TenantCrmEntityContact struct {
|
||||
RelatedID uint64 `orm:"column(related_id)" json:"related_id"`
|
||||
ContactName string `orm:"column(contact_name);size(50)" json:"contact_name"`
|
||||
Position string `orm:"column(position);size(50)" json:"position"`
|
||||
Mobile string `orm:"column(mobile);size(20)" json:"mobile"`
|
||||
Mobile string `orm:"column(mobile);size(20)" json:"mobile"` // 手机号(保留第一个,兼容旧逻辑)
|
||||
// 手机号可登记多个(有的人有多个号码):JSON 数组,最多 5 个,mobile 始终与其中一个(第一个)保持一致
|
||||
Mobiles string `orm:"column(mobiles);type(text);null" json:"mobiles"`
|
||||
Wechat string `orm:"column(wechat);size(64)" json:"wechat"`
|
||||
QQ string `orm:"column(qq);size(20)" json:"qq"`
|
||||
Email string `orm:"column(email);size(100)" json:"email"`
|
||||
|
||||
@@ -9,12 +9,17 @@ import "time"
|
||||
// contract_id 冗余存储,便于按合同直接查询进度列表;
|
||||
// - 每次「新建回款」追加一条记录,构成回款进度(一笔笔实际到账),
|
||||
// 与计划内的 items(计划分期)区分开:前者是实际发生,后者是计划安排;
|
||||
// - 计划表 received_amount 由本表记录金额汇总回写(refreshPlanReceived)。
|
||||
// - 计划表 received_amount 由本表记录金额汇总回写(refreshPlanReceived);
|
||||
// - item_seq / item_name 标记本笔回款对应的计划明细节点(进度 / 分期):
|
||||
// item_seq 对应计划 items 中的 seq(1-based),0=未指定(按整单登记);
|
||||
// item_name 为节点名称快照,便于明细节点被改动后仍可追溯。
|
||||
type TenantCrmPaybackRecord struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
|
||||
ContractID *uint64 `orm:"column(contract_id);null" json:"contract_id"` // 关联合同ID
|
||||
PaybackID uint64 `orm:"column(payback_id)" json:"payback_id"` // 关联回款计划ID
|
||||
ItemSeq int `orm:"column(item_seq);default(0)" json:"item_seq"` // 对应计划明细序号(1-based),0=未指定
|
||||
ItemName string `orm:"column(item_name);size(50)" json:"item_name"` // 计划明细节点名称快照
|
||||
Amount float64 `orm:"column(amount);digits(14);decimals(2);default(0)" json:"amount"` // 本次回款金额
|
||||
ReceivedDate string `orm:"column(received_date);size(20)" json:"received_date"` // 回款日期 YYYY-MM-DD
|
||||
PayMethod int8 `orm:"column(pay_method);default(1)" json:"pay_method"` // 回款方式:1对公/2网银/3现金/4支票/5支付宝/6微信/7其他
|
||||
|
||||
@@ -23,6 +23,7 @@ type TenantCrmProduct struct {
|
||||
TaxRate float64 `orm:"column(tax_rate);digits(6);decimals(2);default(0)" json:"tax_rate"` // 税率(%)
|
||||
LineType string `orm:"column(line_type);size(20);default(product)" json:"line_type"` // 行类型 product/dev
|
||||
DevUnitPrice float64 `orm:"column(dev_unit_price);digits(14);decimals(2);default(0)" json:"dev_unit_price"` // 软件开发统一人天单价
|
||||
DevMode string `orm:"column(dev_mode);size(20);default(self)" json:"dev_mode"` // 软件开发研发方式:self自行研发/outsource外协研发(别人帮我们研发)
|
||||
DevTree string `orm:"column(dev_tree);type(text);null" json:"dev_tree"` // 软件开发模块树JSON文本
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1启用/0停用
|
||||
ProjectID *uint64 `orm:"column(project_id);null" json:"project_id"` // 来源项目ID(由项目生成时填入)
|
||||
|
||||
@@ -6,14 +6,16 @@ import "time"
|
||||
//
|
||||
// 说明:
|
||||
// - 与 CMS 产品分类类似,是 CRM 产品台账的产品归类(如:服务器类 / 软件许可 / 实施服务 等);
|
||||
// - 产品表单的「产品分类」下拉取自该表;status 1启用/0停用。
|
||||
// - 产品表单的「产品分类」下拉取自该表;status 1启用/0停用;
|
||||
// - is_default 1=系统默认分类(「未分类」,由系统确保存在,不可编辑、不可删除,排序置顶)/0=租户自定义分类(可增删改)。
|
||||
type TenantCrmProductCategory struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
|
||||
Name string `orm:"column(name);size(100)" json:"name"` // 分类名称
|
||||
Code string `orm:"column(code);size(50)" json:"code"` // 分类编码(选填)
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"` // 排序
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1启用/0停用
|
||||
Name string `orm:"column(name);size(100)" json:"name"` // 分类名称
|
||||
Code string `orm:"column(code);size(50)" json:"code"` // 分类编码(选填)
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"` // 排序
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1启用/0停用
|
||||
IsDefault int8 `orm:"column(is_default);default(0)" json:"is_default"` // 1系统默认(不可编辑/删除)/0租户自定义
|
||||
Remark string `orm:"column(remark);type(text);null" json:"remark"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`
|
||||
|
||||
@@ -16,18 +16,20 @@ type TenantCrmProject struct {
|
||||
OwnerUserName string `orm:"column(owner_user_name);size(128)" json:"owner_user_name"`
|
||||
Industry string `orm:"column(industry);size(50)" json:"industry"`
|
||||
// 项目类型:1=单一项目(只有上游客户) 2=上下游项目(上游客户 + 下游供应商)
|
||||
// 3=上中游项目(上游 A 公司 + 中游 B 公司,下游固定为本公司)
|
||||
ProjectType int8 `orm:"column(project_type);default(1)" json:"project_type"`
|
||||
// 下游主体:可从供应商库或客户库选择(supplier_ref_type + supplier_id 标明来源),也允许手工填写名称
|
||||
// 对方主体(2=上下游项目的下游 / 3=上中游项目的中游):可从供应商库或客户库选择(supplier_ref_type + supplier_id 标明来源),也允许手工填写名称
|
||||
SupplierID *uint64 `orm:"column(supplier_id);null" json:"supplier_id"`
|
||||
SupplierRefType int8 `orm:"column(supplier_ref_type);default(0)" json:"supplier_ref_type"` // 0未关联 1客户 2供应商
|
||||
SupplierName string `orm:"column(supplier_name);size(100)" json:"supplier_name"`
|
||||
SupplierIndustry string `orm:"column(supplier_industry);size(50)" json:"supplier_industry"`
|
||||
// 金额拆分为上下游:上游=对客户的收入,下游=对供应商的成本(上下游项目毛利 = 上游 - 下游)
|
||||
// 金额拆分为上下游:上游=对客户的收入,下游=对供应商的成本(上下游项目毛利 = 上游 - 下游);
|
||||
// 上中游项目:上游=上游 A 公司合同额,下游字段存中游 B 公司(与我方)合同额
|
||||
UpstreamAmount float64 `orm:"column(upstream_amount);digits(14);decimals(2);default(0)" json:"upstream_amount"`
|
||||
DownstreamAmount float64 `orm:"column(downstream_amount);digits(14);decimals(2);default(0)" json:"downstream_amount"`
|
||||
// Amount 为旧「项目金额」列,已由 UpstreamAmount 取代;写入时始终同步为上游金额,仅作历史兼容
|
||||
Amount float64 `orm:"column(amount);digits(14);decimals(2);default(0)" json:"amount"`
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1未开始/2进行中/3已完成/4已暂停
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1未开始/2进行中/3已完成/4已暂停/5异常
|
||||
// StartDate / EndDate 为旧的手工维护列,已改由关联合同自动汇总,保留仅用于兼容历史数据
|
||||
StartDate *time.Time `orm:"column(start_date);type(date);null" json:"start_date"`
|
||||
EndDate *time.Time `orm:"column(end_date);type(date);null" json:"end_date"`
|
||||
@@ -39,6 +41,12 @@ type TenantCrmProject struct {
|
||||
UpstreamPhone string `orm:"column(upstream_phone);size(20)" json:"upstream_phone"`
|
||||
DownstreamContact string `orm:"column(downstream_contact);size(50)" json:"downstream_contact"`
|
||||
DownstreamPhone string `orm:"column(downstream_phone);size(20)" json:"downstream_phone"`
|
||||
// 项目联系人:从对应企业通讯录中挑选的联系人ID集合(JSON 数组字符串,如 [1,5,8],空为未选)。
|
||||
// 上游=客户方(yz_backend_erp_contact.company_type=customer & company_id=customer_id);
|
||||
// 下游/中游=对方主体方(company_type 按 supplier_ref_type:1=customer 2=supplier,company_id=supplier_id)。
|
||||
// 单一项目只使用上游集合;联系人详情实时来自企业通讯录,此处仅存 ID 引用。
|
||||
UpstreamContactIDs string `orm:"column(upstream_contact_ids);type(text);null" json:"upstream_contact_ids"`
|
||||
DownstreamContactIDs string `orm:"column(downstream_contact_ids);type(text);null" json:"downstream_contact_ids"`
|
||||
// 以下为旧版单一对接人信息,已被上下游对接人取代,仅保留列以兼容历史数据
|
||||
ContactPerson string `orm:"column(contact_person);size(50)" json:"contact_person"`
|
||||
ContactPosition string `orm:"column(contact_position);size(50)" json:"contact_position"` // 对接人职位(已废弃)
|
||||
|
||||
@@ -7,15 +7,17 @@ import "time"
|
||||
// 说明:
|
||||
// - 维护产品、合同等业务使用的计量单位(套 / 台 / 个 / 人天 …);
|
||||
// - 在「CRM -> 基本设置 -> 单位设置」中维护,产品表单的「单位」下拉取自该表;
|
||||
// - is_default 1=系统默认单位(由系统写入,不可编辑、不可删除)/0=租户自定义单位(可增删改);
|
||||
// - status 1启用/0停用;同租户下单位名称唯一(uk_tenant_name)。
|
||||
type TenantCrmUnit struct {
|
||||
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
|
||||
Name string `orm:"column(name);size(20)" json:"name"` // 单位名称
|
||||
Code string `orm:"column(code);size(50)" json:"code"` // 单位编码(选填)
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"` // 排序
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1启用/0停用
|
||||
Remark string `orm:"column(remark);size(255)" json:"remark"` // 备注
|
||||
Name string `orm:"column(name);size(20)" json:"name"` // 单位名称
|
||||
Code string `orm:"column(code);size(50)" json:"code"` // 单位编码(选填)
|
||||
Sort int `orm:"column(sort);default(0)" json:"sort"` // 排序
|
||||
Status int8 `orm:"column(status);default(1)" json:"status"` // 1启用/0停用
|
||||
IsDefault int8 `orm:"column(is_default);default(0)" json:"is_default"` // 1系统默认(不可编辑/删除)/0租户自定义
|
||||
Remark string `orm:"column(remark);size(255)" json:"remark"` // 备注
|
||||
CreateUserID string `orm:"column(create_user_id);size(64)" json:"create_user_id"`
|
||||
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
||||
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`
|
||||
|
||||
Reference in New Issue
Block a user