package packagecustomer import ( "context" "strings" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" "git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/model" ) const ( sysDeptTable = "sys_dept" cardInfoTable = "t_sim_card_info" flowPackageTable = "t_sim_flow_package_info" packageCustomerTable = "t_package_customer" ) var ErrDeptNotFound = gerror.New("package customer sync dept not found") type Service struct { db gdb.DB } type deptRow struct { DeptId int64 `orm:"dept_id"` ParentId int64 `orm:"parent_id"` Ancestors string `orm:"ancestors"` DeptName string `orm:"dept_name"` } type packageRow struct { PackageCode string `orm:"package_code"` PackageName string `orm:"package_name"` } func New() *Service { return &Service{} } func (s *Service) SyncDeptPackages(ctx context.Context, message model.PackageCustomerSyncMessage) error { message.TenantId = strings.TrimSpace(message.TenantId) message.Trigger = strings.TrimSpace(message.Trigger) if message.TenantId == "" { return gerror.New("package customer sync tenantId is empty") } if message.DeptId <= 0 { return gerror.New("package customer sync deptId is empty") } var packageCount int err := s.database().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { dept, err := s.lockDept(ctx, tx, message.TenantId, message.DeptId) if err != nil { return err } packages, err := s.loadPackages(ctx, tx, message.TenantId, dept) if err != nil { return err } packageCount = len(packages) return s.rebuild(ctx, tx, message.TenantId, dept, message.UserId, packages) }) if err != nil { return err } g.Log().Infof(ctx, "package customer sync finished, tenantId:%s, deptId:%d, packages:%d, trigger:%s, sourceBatchNo:%s", message.TenantId, message.DeptId, packageCount, message.Trigger, message.SourceBatchNo) return nil } func (s *Service) database() gdb.DB { if s.db != nil { return s.db } return g.DB() } func (s *Service) lockDept(ctx context.Context, tx gdb.TX, tenantId string, deptId int64) (*deptRow, error) { var dept *deptRow err := tx.Ctx(ctx).Model(sysDeptTable).Safe(). Fields("dept_id", "parent_id", "ancestors", "dept_name"). Where("tenant_id", tenantId). Where("dept_id", deptId). WhereNull("deleted_at"). LockUpdate(). Limit(1). Scan(&dept) if err != nil { return nil, gerror.Wrap(err, "load package customer sync dept failed") } if dept == nil || dept.DeptId <= 0 { return nil, ErrDeptNotFound } return dept, nil } func (s *Service) loadPackages(ctx context.Context, tx gdb.TX, tenantId string, dept *deptRow) ([]packageRow, error) { if deptIsTop(dept) { var packages []packageRow err := tx.Ctx(ctx).Model(flowPackageTable).Safe(). Fields("package_code", "package_name"). Where("tenant_id", tenantId). Scan(&packages) if err != nil { return nil, gerror.Wrap(err, "load top dept packages failed") } return packages, nil } var packages []packageRow err := tx.Ctx(ctx).Model(cardInfoTable+" c").Safe(). LeftJoin(flowPackageTable+" p", "c.current_package_code = p.package_code"). Fields("DISTINCT c.current_package_code AS package_code", "p.package_name AS package_name"). Where("c.tenant_id", tenantId). Where("c.dept_id", dept.DeptId). Where("p.tenant_id", tenantId). Where("c.current_package_code IS NOT NULL"). Where("c.current_package_code <> ?", ""). Where("p.package_code IS NOT NULL"). Scan(&packages) if err != nil { return nil, gerror.Wrap(err, "load dept packages failed") } return packages, nil } func (s *Service) rebuild(ctx context.Context, tx gdb.TX, tenantId string, dept *deptRow, userId int64, packages []packageRow) error { if _, err := tx.Ctx(ctx).Model(packageCustomerTable).Safe(). Where("tenant_id", tenantId). Where("dept_id", dept.DeptId). Delete(); err != nil { return gerror.Wrap(err, "clear dept package customer relation failed") } now := gtime.Now() rows := make([]g.Map, 0, len(packages)) seen := make(map[string]struct{}, len(packages)) for _, item := range packages { packageCode := strings.TrimSpace(item.PackageCode) if packageCode == "" { continue } if _, ok := seen[packageCode]; ok { continue } seen[packageCode] = struct{}{} rows = append(rows, g.Map{ "package_code": packageCode, "package_name": strings.TrimSpace(item.PackageName), "dept_id": dept.DeptId, "dept_name": strings.TrimSpace(dept.DeptName), "tenant_id": tenantId, "created_dept": dept.DeptId, "created_by": userId, "created_at": now, "updated_by": userId, "updated_at": now, }) } if len(rows) == 0 { return nil } if _, err := tx.Ctx(ctx).Model(packageCustomerTable).Safe().Data(rows).Insert(); err != nil { return gerror.Wrap(err, "insert dept package customer relation failed") } return nil } func deptIsTop(dept *deptRow) bool { if dept == nil { return false } return dept.ParentId == 0 || strings.Trim(dept.Ancestors, ",") == "0" }