Files
junhong_cmp_fiber/internal/model/employee_collection.go
break ce24d5612e
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m20s
feat(员工代收款): 新增员工代收款账单闭环
- 新增 6 张表与成对迁移 000212,扩展企业微信审批场景业务类型白名单
- 后台线下套餐订单与两条代理线下充值入账路径在来源成功事务内建账,来源唯一键幂等
- 核销申请、审批尝试记录、账单分摊预占与驳回重提,审批业务类型 employee_collection_approval
- 企业微信终态消费幂等:通过转已核销、驳回释放预占、通过后撤销不回滚并转异常终态
- 退款成功事务内按 bill_id+refund_id 幂等冲销账单或仅写退款关联提示
- 线下收款方式字典、账单查询/统计/关闭、申请查询与代办权限,均写入事务内审计

OpenSpec Change: add-employee-collection-bills
2026-09-10 18:24:05 +08:00

151 lines
13 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"time"
"gorm.io/datatypes"
"gorm.io/gorm"
)
// EmployeeCollectionPaymentMethod 是线下收款方式字典项。
// 状态语义见 constants.EmployeeCollectionPaymentMethodStatus*;被业务引用后只可停用。
type EmployeeCollectionPaymentMethod struct {
gorm.Model
BaseModel `gorm:"embedded"`
Code string `gorm:"column:code;type:varchar(64);not null;comment:稳定编码,未删除记录中唯一" json:"code"`
Name string `gorm:"column:name;type:varchar(100);not null;comment:收款方式名称" json:"name"`
SortOrder int64 `gorm:"column:sort_order;type:bigint;not null;default:0;comment:排序值,从 0 递增" json:"sort_order"`
Status int `gorm:"column:status;type:smallint;not null;default:1;comment:状态 0-禁用 1-启用" json:"status"`
Remark string `gorm:"column:remark;type:varchar(500);not null;default:'';comment:备注" json:"remark"`
}
// TableName 指定线下收款方式字典表名。
func (EmployeeCollectionPaymentMethod) TableName() string {
return "tb_employee_collection_payment_method"
}
// EmployeeCollectionBill 是后台账号代客户经办业务形成的本地暂挂欠款。
// 由来源成功事务按来源唯一键 SourceKey 幂等创建,不存在历史扫描或手工建账路径。
type EmployeeCollectionBill struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
SourceType string `gorm:"column:source_type;type:varchar(20);not null;comment:来源类型 order/recharge" json:"source_type"`
SourceID uint `gorm:"column:source_id;not null;comment:来源业务主键ID" json:"source_id"`
SourceKey string `gorm:"column:source_key;type:varchar(64);not null;comment:来源唯一键 order:{id} / recharge:{id}" json:"source_key"`
SourceNo string `gorm:"column:source_no;type:varchar(64);not null;default:'';comment:来源单号快照" json:"source_no"`
DebtorAccountID uint `gorm:"column:debtor_account_id;not null;comment:欠款人后台账号ID" json:"debtor_account_id"`
DebtorSnapshot datatypes.JSON `gorm:"column:debtor_snapshot;type:jsonb;not null;comment:欠款人账号快照" json:"debtor_snapshot"`
CustomerSnapshot datatypes.JSON `gorm:"column:customer_snapshot;type:jsonb;not null;comment:来源客户或店铺只读快照" json:"customer_snapshot"`
ReceivableAmount int64 `gorm:"column:receivable_amount;type:bigint;not null;comment:应收金额(分)" json:"receivable_amount"`
ReceivedAmount int64 `gorm:"column:received_amount;type:bigint;not null;default:0;comment:已核销金额(分)" json:"received_amount"`
ReservedAmount int64 `gorm:"column:reserved_amount;type:bigint;not null;default:0;comment:审批中预占金额(分)" json:"reserved_amount"`
Status int `gorm:"column:status;type:smallint;not null;default:0;comment:状态 0-待核销 1-部分核销 2-已核销 3-已关闭" json:"status"`
ClosedReason string `gorm:"column:closed_reason;type:varchar(500);not null;default:'';comment:关闭原因" json:"closed_reason"`
ClosedAt *time.Time `gorm:"column:closed_at;type:timestamptz;comment:关闭时间" json:"closed_at,omitempty"`
Creator uint `gorm:"column:creator;not null;default:0;comment:创建人用户ID" json:"creator"`
Updater uint `gorm:"column:updater;not null;default:0;comment:最近更新人用户ID" json:"updater"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null;autoUpdateTime" json:"updated_at"`
}
// TableName 指定员工代收款账单表名。
func (EmployeeCollectionBill) TableName() string {
return "tb_employee_collection_bill"
}
// EmployeeCollectionApplication 是一笔外部付款的核销申请只保存最新审批实例ID用于展示。
type EmployeeCollectionApplication struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
ApplicantAccountID uint `gorm:"column:applicant_account_id;not null;comment:申请人后台账号ID" json:"applicant_account_id"`
ActingOperatorID uint `gorm:"column:acting_operator_id;not null;default:0;comment:实际代办的超级管理员账号ID0 表示本人办理" json:"acting_operator_id"`
ActingReason string `gorm:"column:acting_reason;type:varchar(500);not null;default:'';comment:代办原因" json:"acting_reason"`
PaymentMethodID uint `gorm:"column:payment_method_id;not null;comment:线下收款方式字典ID" json:"payment_method_id"`
PaymentMethodCode string `gorm:"column:payment_method_code;type:varchar(64);not null;comment:收款方式编码快照" json:"payment_method_code"`
PaymentMethodName string `gorm:"column:payment_method_name;type:varchar(100);not null;comment:收款方式名称快照" json:"payment_method_name"`
PaidAmount int64 `gorm:"column:paid_amount;type:bigint;not null;comment:人工确认付款金额(分)" json:"paid_amount"`
PayerName string `gorm:"column:payer_name;type:varchar(100);not null;default:'';comment:付款方名称" json:"payer_name"`
PaidAt time.Time `gorm:"column:paid_at;type:timestamptz;not null;comment:付款时间" json:"paid_at"`
ExternalTransactionNo string `gorm:"column:external_transaction_no;type:varchar(128);not null;default:'';comment:外部交易流水号" json:"external_transaction_no"`
PaymentVoucherKeys StringJSONBArray `gorm:"column:payment_voucher_keys;type:jsonb;not null;comment:支付凭证对象存储Key列表" json:"payment_voucher_keys"`
Remark string `gorm:"column:remark;type:varchar(500);not null;default:'';comment:申请备注" json:"remark"`
Status int `gorm:"column:status;type:smallint;not null;default:0;comment:状态 0-审批中 1-已通过 2-已驳回 3-已撤销或已关闭" json:"status"`
LatestAttemptID uint `gorm:"column:latest_attempt_id;not null;default:0;comment:最新审批尝试记录ID" json:"latest_attempt_id"`
LatestApprovalInstanceID uint `gorm:"column:latest_approval_instance_id;not null;default:0;comment:最新通用审批实例ID" json:"latest_approval_instance_id"`
DecidedAt *time.Time `gorm:"column:decided_at;type:timestamptz;comment:审批终态到达时间" json:"decided_at,omitempty"`
TerminalReason string `gorm:"column:terminal_reason;type:varchar(500);not null;default:'';comment:异常终态说明" json:"terminal_reason"`
Creator uint `gorm:"column:creator;not null;default:0;comment:创建人用户ID" json:"creator"`
Updater uint `gorm:"column:updater;not null;default:0;comment:最近更新人用户ID" json:"updater"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null;autoUpdateTime" json:"updated_at"`
}
// TableName 指定核销申请表名。
func (EmployeeCollectionApplication) TableName() string {
return "tb_employee_collection_application"
}
// EmployeeCollectionApplicationAttempt 是同一申请每次提交或重提对应的不可变审批材料。
// 其主键同时作为通用审批实例的业务ID使每次提交各自持有独立审批实例。
type EmployeeCollectionApplicationAttempt struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
ApplicationID uint `gorm:"column:application_id;not null;comment:所属核销申请ID" json:"application_id"`
AttemptNo int `gorm:"column:attempt_no;type:int;not null;comment:第几次提交,从 1 递增" json:"attempt_no"`
PaymentMethodID uint `gorm:"column:payment_method_id;not null;comment:本次冻结的收款方式字典ID" json:"payment_method_id"`
PaymentMethodCode string `gorm:"column:payment_method_code;type:varchar(64);not null;comment:本次冻结的收款方式编码" json:"payment_method_code"`
PaymentMethodName string `gorm:"column:payment_method_name;type:varchar(100);not null;comment:本次冻结的收款方式名称" json:"payment_method_name"`
PaidAmount int64 `gorm:"column:paid_amount;type:bigint;not null;comment:本次冻结的付款金额(分)" json:"paid_amount"`
PayerName string `gorm:"column:payer_name;type:varchar(100);not null;default:'';comment:本次冻结的付款方名称" json:"payer_name"`
PaidAt time.Time `gorm:"column:paid_at;type:timestamptz;not null;comment:本次冻结的付款时间" json:"paid_at"`
ExternalTransactionNo string `gorm:"column:external_transaction_no;type:varchar(128);not null;default:'';comment:本次冻结的外部交易流水号" json:"external_transaction_no"`
PaymentVoucherKeys StringJSONBArray `gorm:"column:payment_voucher_keys;type:jsonb;not null;comment:本次冻结的支付凭证对象键列表" json:"payment_voucher_keys"`
Remark string `gorm:"column:remark;type:varchar(500);not null;default:'';comment:本次冻结的备注" json:"remark"`
SubmittedByAccountID uint `gorm:"column:submitted_by_account_id;not null;comment:本次实际提交账号ID" json:"submitted_by_account_id"`
ActingReason string `gorm:"column:acting_reason;type:varchar(500);not null;default:'';comment:本次代办原因" json:"acting_reason"`
AllocationSnapshot datatypes.JSON `gorm:"column:allocation_snapshot;type:jsonb;not null;comment:本次冻结的账单分摊快照" json:"allocation_snapshot"`
ApprovalInstanceID *uint `gorm:"column:approval_instance_id;comment:本次尝试关联的通用审批实例ID" json:"approval_instance_id,omitempty"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
}
// TableName 指定审批尝试记录表名。
func (EmployeeCollectionApplicationAttempt) TableName() string {
return "tb_employee_collection_application_attempt"
}
// EmployeeCollectionApplicationAllocation 是申请对单张账单的本次分摊。
// 审批中预占账单余额,终态释放预占或转入已核销金额。
type EmployeeCollectionApplicationAllocation struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
ApplicationID uint `gorm:"column:application_id;not null;comment:所属核销申请ID" json:"application_id"`
AttemptID uint `gorm:"column:attempt_id;not null;comment:所属审批尝试记录ID" json:"attempt_id"`
BillID uint `gorm:"column:bill_id;not null;comment:目标账单ID" json:"bill_id"`
Amount int64 `gorm:"column:amount;type:bigint;not null;comment:本次分摊金额(分)" json:"amount"`
Status int `gorm:"column:status;type:smallint;not null;default:0;comment:状态 0-审批中预占 1-已通过 2-已驳回或已释放" json:"status"`
ReleasedAt *time.Time `gorm:"column:released_at;type:timestamptz;comment:预占释放时间" json:"released_at,omitempty"`
Creator uint `gorm:"column:creator;not null;default:0;comment:创建人用户ID" json:"creator"`
Updater uint `gorm:"column:updater;not null;default:0;comment:最近更新人用户ID" json:"updater"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null;autoUpdateTime" json:"updated_at"`
}
// TableName 指定申请分摊表名。
func (EmployeeCollectionApplicationAllocation) TableName() string {
return "tb_employee_collection_application_allocation"
}
// EmployeeCollectionBillRefund 是来源订单退款与账单之间的唯一冲销关联事实。
type EmployeeCollectionBillRefund struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
BillID uint `gorm:"column:bill_id;not null;comment:目标账单ID" json:"bill_id"`
RefundID uint `gorm:"column:refund_id;not null;comment:退款申请ID" json:"refund_id"`
SourceOrderID uint `gorm:"column:source_order_id;not null;comment:账单来源订单ID" json:"source_order_id"`
RefundAmount int64 `gorm:"column:refund_amount;type:bigint;not null;comment:本次退款成功金额(分)" json:"refund_amount"`
BillReceivableAmount int64 `gorm:"column:bill_receivable_amount;type:bigint;not null;comment:冲销前账单应收金额快照(分)" json:"bill_receivable_amount"`
Outcome string `gorm:"column:outcome;type:varchar(20);not null;comment:处理结果 closed_full/reduced/hint_only" json:"outcome"`
ReducedAmount int64 `gorm:"column:reduced_amount;type:bigint;not null;default:0;comment:实际冲减应收金额(分)" json:"reduced_amount"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
}
// TableName 指定退款冲销关联表名。
func (EmployeeCollectionBillRefund) TableName() string {
return "tb_employee_collection_bill_refund"
}