Files
kefu/im/backend/internal/app/pet_address_purge.go
Your NameandClaude Opus 5 9345805133 代喂改走真实订单,并补上打卡纪律与地址明文清除
支付原来是个占位:调一下接口任务就算"已付"。现在任务和喂养者保证金都
走会员那套订单与支付网关,一笔订单买到什么由 applyPaidOrderTx 统一决定,
沙箱和真实回调走同一段逻辑。退款能释放托管中的任务,但不会去动已经结算
的那一笔——钱已经在喂养者账上,那种情况必须有人看过再说。

通道接通之前,客服可以在管理端手工标记已托管,必须写明钱怎么收的,进审计日志。

另外补上三件方案里写了但代码没做的事:打卡必须按到达、喂食、离开的顺序,
喂食离到达太近视为摆拍;地址新增紧急联系人与常去医院,随门牌一起只发给
被选中的喂养者;任务结束七天后由后台任务抹掉地址明文,只留城市与街道。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 09:07:38 +08:00

72 lines
2.5 KiB
Go

package app
import (
"context"
"log"
"time"
)
// The address table holds a stranger's door number and phone. Keeping that
// after the job is over buys nothing and costs a lot if the database ever
// leaks, so a finished task schedules its address for erasure and this worker
// carries it out. The city and street stay: they are what the history reads
// from, and they were public on the listing anyway.
func (a *App) scheduleAddressPurge(ctx context.Context) int64 {
days := a.configInt(ctx, "pet.address_purge_days", 7)
if days < 1 {
days = 7
}
// 只给"没有任何进行中任务"的地址排期;主人常用的地址不会因为一次任务结束就被清空。
result, err := a.db.ExecContext(ctx, `UPDATE pet_addresses addr
JOIN (SELECT address_id,MAX(updated_at) AS finished FROM pet_feed_tasks
WHERE status IN ('SETTLED','REFUNDED','CANCELLED','ARBITRATED') GROUP BY address_id) ended
ON ended.address_id=addr.id
SET addr.purge_at=DATE_ADD(ended.finished,INTERVAL ? DAY)
WHERE addr.purge_at IS NULL
AND NOT EXISTS (SELECT 1 FROM pet_feed_tasks live WHERE live.address_id=addr.id
AND live.status IN ('CREATED','ESCROWED','ASSIGNED','SERVING','COMPLETED','DISPUTED'))`, days)
if err != nil {
log.Printf("pet address purge scheduling failed: %v", err)
return 0
}
affected, _ := result.RowsAffected()
return affected
}
func (a *App) purgeDueAddresses(ctx context.Context) int64 {
// 一个地址重新被用于新任务时会清掉 purge_at;这里再确认一次没有活任务,
// 免得排期和复用之间抢到一起。
result, err := a.db.ExecContext(ctx, `UPDATE pet_addresses addr
SET addr.detail_cipher='',addr.contact_cipher='',addr.emergency_cipher=NULL,addr.vet_hospital='',
addr.latitude=NULL,addr.longitude=NULL,addr.purge_at=NULL
WHERE addr.purge_at IS NOT NULL AND addr.purge_at<=NOW(3)
AND NOT EXISTS (SELECT 1 FROM pet_feed_tasks live WHERE live.address_id=addr.id
AND live.status IN ('CREATED','ESCROWED','ASSIGNED','SERVING','COMPLETED','DISPUTED'))`)
if err != nil {
log.Printf("pet address purge failed: %v", err)
return 0
}
affected, _ := result.RowsAffected()
if affected > 0 {
log.Printf("pet address purge: cleared plaintext for %d addresses", affected)
}
return affected
}
func (a *App) startAddressPurgeWorker(ctx context.Context) {
go func() {
ticker := time.NewTicker(time.Hour)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
a.scheduleAddressPurge(ctx)
a.purgeDueAddresses(ctx)
}
}
}()
}