| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- package initialize
- import (
- "errors"
- "fmt"
- "gorm.io/gorm"
- "wails-app/internal/dao"
- "wails-app/internal/global"
- )
- type paymentMethodDefault struct {
- Code string
- Name string
- InputMode string
- Scenes []string
- Enabled bool
- Sort int
- Description string
- }
- type paymentEntryDefault struct {
- Code string
- Name string
- Enabled bool
- Sort int
- Description string
- Methods []string
- }
- // EnsurePaymentConfiguration upgrades both new and existing databases. The
- // method and entry tables are deliberately seeded independently: an entry
- // controls where payment starts, while a method controls how it settles.
- func EnsurePaymentConfiguration() error {
- db := global.GVA_DB
- if db == nil {
- return nil
- }
- if err := db.AutoMigrate(&dao.PaymentEntryConfig{}, &dao.PaymentEntryMethod{}); err != nil {
- return fmt.Errorf("初始化支付入口表失败: %w", err)
- }
- methods := []paymentMethodDefault{
- {Code: "cash", Name: "人工支付", InputMode: "manual_amount", Scenes: []string{"counter"}, Enabled: true, Sort: 10, Description: "岗亭人员录入实收金额并确认收款"},
- {Code: "pos", Name: "POS机支付", InputMode: "confirm", Scenes: []string{"counter"}, Enabled: false, Sort: 20, Description: "通过POS机完成支付后由岗亭人员确认"},
- {Code: "ticket_qr", Name: "小票扫码支付", InputMode: "external", Scenes: []string{"ticket"}, Enabled: false, Sort: 30, Description: "车主扫描停车小票发起外部支付"},
- }
- for _, item := range methods {
- method := dao.PaymentMethodConfig{}
- err := db.Where("code = ?", item.Code).First(&method).Error
- if errors.Is(err, gorm.ErrRecordNotFound) {
- method = dao.PaymentMethodConfig{
- Code: item.Code, Name: item.Name, InputMode: item.InputMode, Scenes: item.Scenes,
- Enabled: item.Enabled, Sort: item.Sort, IsSystem: true, Description: item.Description,
- }
- err = db.Create(&method).Error
- }
- if err != nil {
- return fmt.Errorf("初始化支付方式 %s 失败: %w", item.Code, err)
- }
- }
- // 人工支付是基础能力,升级时也要修复旧数据中被关闭或改型的情况。
- cashDefaults := dao.PaymentMethodConfig{
- Enabled: true, InputMode: "manual_amount", Scenes: []string{"counter"}, IsSystem: true,
- }
- if err := db.Model(&dao.PaymentMethodConfig{}).Where("code = ?", "cash").
- Select("enabled", "input_mode", "scenes", "is_system").Updates(&cashDefaults).Error; err != nil {
- return err
- }
- entries := []paymentEntryDefault{
- {Code: "counter", Name: "收费岗亭", Enabled: true, Sort: 10, Description: "由收费岗亭人员发起收费和放行", Methods: []string{"cash", "pos"}},
- {Code: "ticket", Name: "停车小票", Enabled: true, Sort: 20, Description: "由停车小票或数字票发起后续支付", Methods: []string{"cash", "pos", "ticket_qr"}},
- }
- for _, item := range entries {
- entry := dao.PaymentEntryConfig{}
- err := db.Where("code = ?", item.Code).First(&entry).Error
- if errors.Is(err, gorm.ErrRecordNotFound) {
- entry = dao.PaymentEntryConfig{
- Code: item.Code, Name: item.Name, Enabled: item.Enabled, Sort: item.Sort,
- IsSystem: true, Description: item.Description,
- }
- if err = db.Create(&entry).Error; err != nil {
- return fmt.Errorf("初始化支付入口 %s 失败: %w", item.Code, err)
- }
- }
- if err != nil {
- return fmt.Errorf("读取支付入口 %s 失败: %w", item.Code, err)
- }
- var relationCount int64
- if err := db.Model(&dao.PaymentEntryMethod{}).Where("entry_code = ?", item.Code).Count(&relationCount).Error; err != nil {
- return err
- }
- if relationCount == 0 {
- for i, methodCode := range item.Methods {
- if err := db.Create(&dao.PaymentEntryMethod{EntryCode: item.Code, MethodCode: methodCode, Sort: i * 10}).Error; err != nil {
- return fmt.Errorf("初始化支付入口 %s 关联失败: %w", item.Code, err)
- }
- }
- }
- }
- // Migrate old method.scenes values into the relation table without
- // overwriting any explicit entry configuration made by an administrator.
- var legacyMethods []dao.PaymentMethodConfig
- if err := db.Where("is_legacy = ?", false).Find(&legacyMethods).Error; err != nil {
- return err
- }
- for _, method := range legacyMethods {
- for _, entryCode := range method.Scenes {
- var entry dao.PaymentEntryConfig
- if err := db.Where("code = ?", entryCode).First(&entry).Error; err != nil {
- continue
- }
- var count int64
- if err := db.Model(&dao.PaymentEntryMethod{}).Where("entry_code = ? AND method_code = ?", entryCode, method.Code).Count(&count).Error; err != nil {
- return err
- }
- if count == 0 {
- if err := db.Create(&dao.PaymentEntryMethod{EntryCode: entryCode, MethodCode: method.Code, Sort: method.Sort}).Error; err != nil {
- return err
- }
- }
- }
- }
- var parkingMenu dao.SysBaseMenu
- if err := db.Where("name = ?", "parking").First(&parkingMenu).Error; err == nil {
- methodMenu, err := ensurePaymentMenu(db, parkingMenu.ID, "paymentMethodConfig", "paymentMethod", "view/parking/paymentMethod.vue", "支付方式", "credit-card", 8)
- if err != nil {
- return err
- }
- entryMenu, err := ensurePaymentMenu(db, parkingMenu.ID, "paymentEntryConfig", "paymentEntry", "view/parking/paymentEntry.vue", "支付入口", "connection", 9)
- if err != nil {
- return err
- }
- ticketMenu, err := ensurePaymentMenu(db, parkingMenu.ID, "digitalTicket", "digitalTicket", "view/parking/digitalTicket.vue", "数字票", "tickets", 10)
- if err != nil {
- return err
- }
- for _, menu := range []*dao.SysBaseMenu{methodMenu, entryMenu} {
- for _, authorityID := range []string{"888", "9527"} {
- var count int64
- if err := db.Model(&dao.SysAuthorityMenu{}).
- Where("sys_base_menu_id = ? AND sys_authority_authority_id = ?", menu.ID, authorityID).Count(&count).Error; err != nil {
- return fmt.Errorf("初始化支付菜单权限失败: %w", err)
- }
- if count == 0 {
- link := dao.SysAuthorityMenu{MenuId: fmt.Sprint(menu.ID), AuthorityId: authorityID}
- if err := db.Create(&link).Error; err != nil {
- return fmt.Errorf("初始化支付菜单权限失败: %w", err)
- }
- }
- }
- }
- for _, authorityID := range []string{"618", "888", "9527"} {
- var count int64
- if err := db.Model(&dao.SysAuthorityMenu{}).
- Where("sys_base_menu_id = ? AND sys_authority_authority_id = ?", ticketMenu.ID, authorityID).Count(&count).Error; err != nil {
- return fmt.Errorf("初始化数字票菜单权限失败: %w", err)
- }
- if count == 0 {
- link := dao.SysAuthorityMenu{MenuId: fmt.Sprint(ticketMenu.ID), AuthorityId: authorityID}
- if err := db.Create(&link).Error; err != nil {
- return fmt.Errorf("初始化数字票菜单权限失败: %w", err)
- }
- }
- }
- }
- apis := []dao.SysApi{
- {Path: "/payment/methods", Description: "查询支付方式配置", ApiGroup: "支付方式", Method: "GET"},
- {Path: "/payment/methods/enabled", Description: "查询入口可用支付方式", ApiGroup: "支付方式", Method: "GET"},
- {Path: "/payment/methods/options", Description: "查询支付方式选项", ApiGroup: "支付方式", Method: "GET"},
- {Path: "/payment/methods", Description: "新增支付方式", ApiGroup: "支付方式", Method: "POST"},
- {Path: "/payment/methods/:id", Description: "更新支付方式", ApiGroup: "支付方式", Method: "PUT"},
- {Path: "/payment/methods/:id/status", Description: "启停支付方式", ApiGroup: "支付方式", Method: "PATCH"},
- {Path: "/payment/methods/:id", Description: "删除支付方式", ApiGroup: "支付方式", Method: "DELETE"},
- {Path: "/payment/entries", Description: "查询支付入口配置", ApiGroup: "支付入口", Method: "GET"},
- {Path: "/payment/entries/enabled", Description: "查询启用的支付入口", ApiGroup: "支付入口", Method: "GET"},
- {Path: "/payment/entries/options", Description: "查询支付入口选项", ApiGroup: "支付入口", Method: "GET"},
- {Path: "/payment/entries", Description: "新增支付入口", ApiGroup: "支付入口", Method: "POST"},
- {Path: "/payment/entries/:id", Description: "更新支付入口", ApiGroup: "支付入口", Method: "PUT"},
- {Path: "/payment/entries/:id/status", Description: "启停支付入口", ApiGroup: "支付入口", Method: "PATCH"},
- {Path: "/payment/entries/:id", Description: "删除支付入口", ApiGroup: "支付入口", Method: "DELETE"},
- {Path: "/digital-ticket/summary", Description: "查询数字票汇总", ApiGroup: "数字票", Method: "GET"},
- {Path: "/digital-ticket/list", Description: "查询数字票列表", ApiGroup: "数字票", Method: "GET"},
- {Path: "/digital-ticket/:ticketNo", Description: "查询数字票详情", ApiGroup: "数字票", Method: "GET"},
- {Path: "/digital-ticket/:ticketNo/pay", Description: "确认数字票支付", ApiGroup: "数字票", Method: "POST"},
- {Path: "/digital-ticket/:ticketNo/exit", Description: "确认数字票离场", ApiGroup: "数字票", Method: "POST"},
- }
- for _, api := range apis {
- var existing dao.SysApi
- err := db.Where("path = ? AND method = ?", api.Path, api.Method).First(&existing).Error
- if errors.Is(err, gorm.ErrRecordNotFound) {
- err = db.Create(&api).Error
- }
- if err != nil {
- return fmt.Errorf("初始化支付API失败: %w", err)
- }
- }
- if err := db.Exec(`CREATE TABLE IF NOT EXISTS casbin_rule (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- ptype TEXT, v0 TEXT, v1 TEXT, v2 TEXT, v3 TEXT, v4 TEXT, v5 TEXT
- )`).Error; err != nil {
- return err
- }
- readRules := [][2]string{
- {"/payment/methods/enabled", "GET"}, {"/payment/methods/options", "GET"},
- {"/payment/entries/enabled", "GET"}, {"/payment/entries/options", "GET"},
- }
- for _, role := range []string{"618", "888", "9527"} {
- for _, rule := range readRules {
- if err := ensureCasbinRule(role, rule[0], rule[1]); err != nil {
- return err
- }
- }
- }
- for _, role := range []string{"888", "9527"} {
- for _, rule := range [][2]string{
- {"/payment/methods", "GET"}, {"/payment/methods", "POST"},
- {"/payment/methods/:id", "PUT"}, {"/payment/methods/:id/status", "PATCH"},
- {"/payment/methods/:id", "DELETE"},
- {"/payment/entries", "GET"}, {"/payment/entries", "POST"},
- {"/payment/entries/:id", "PUT"}, {"/payment/entries/:id/status", "PATCH"},
- {"/payment/entries/:id", "DELETE"},
- } {
- if err := ensureCasbinRule(role, rule[0], rule[1]); err != nil {
- return err
- }
- }
- }
- for _, role := range []string{"618", "888", "9527"} {
- for _, rule := range [][2]string{
- {"/digital-ticket/summary", "GET"},
- {"/digital-ticket/list", "GET"},
- {"/digital-ticket/:ticketNo", "GET"},
- {"/digital-ticket/:ticketNo/pay", "POST"},
- {"/digital-ticket/:ticketNo/exit", "POST"},
- } {
- if err := ensureCasbinRule(role, rule[0], rule[1]); err != nil {
- return err
- }
- }
- }
- return nil
- }
- func ensurePaymentMenu(db *gorm.DB, parentID uint, name, path, component, title, icon string, sort int) (*dao.SysBaseMenu, error) {
- menu := &dao.SysBaseMenu{}
- err := db.Where("name = ?", name).First(menu).Error
- if errors.Is(err, gorm.ErrRecordNotFound) {
- *menu = dao.SysBaseMenu{
- MenuLevel: 0, ParentId: parentID, Path: path, Name: name,
- Hidden: false, Component: component, Sort: sort,
- Meta: dao.Meta{Title: title, Icon: icon},
- }
- if err := db.Create(menu).Error; err != nil {
- return nil, fmt.Errorf("初始化%s菜单失败: %w", title, err)
- }
- return menu, nil
- }
- if err != nil {
- return nil, fmt.Errorf("读取%s菜单失败: %w", title, err)
- }
- if err := db.Model(menu).Updates(map[string]interface{}{"parent_id": parentID, "path": path, "component": component, "sort": sort}).Error; err != nil {
- return nil, fmt.Errorf("更新%s菜单失败: %w", title, err)
- }
- return menu, nil
- }
- func ensureCasbinRule(role, path, method string) error {
- db := global.GVA_DB
- var count int64
- if err := db.Table("casbin_rule").Where("ptype = ? AND v0 = ? AND v1 = ? AND v2 = ?", "p", role, path, method).Count(&count).Error; err != nil {
- return err
- }
- if count == 0 {
- return db.Exec("INSERT INTO casbin_rule (ptype, v0, v1, v2, v3, v4, v5) VALUES (?, ?, ?, ?, '', '', '')", "p", role, path, method).Error
- }
- return nil
- }
|