feat(wallet): reconcile balances, ledger and lots on a schedule
Adds the reconciliation of docs/prd-point-coin.md §7.5 (PC-108). One aggregate query per check, across every wallet: - wallet balance = SUM(ledger), per currency, including customers with ledger rows but no wallet row - wallet balance = SUM(lot remaining) - lot original - SUM(allocations) = remaining - SUM(allocations) = |amount| for every deduction - lots created = amount for every addition, which the engine keeps and the other checks rely on The check on payments.points_used waits for that column (PC-305). WalletReconciliationJob runs the checks at startup and every six hours, alongside the omset scheduler. It is silent while the data is consistent. Each discrepancy is logged with its check, customer, object and the expected and actual values, and the organization's admins, owners and managers get a high-priority notification. An organization is notified again only when its set of discrepancies changes. Nothing is corrected automatically. At most 50 discrepancies per check are reported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a6d5a8b056
commit
040780cd2d
@@ -31,6 +31,7 @@ type App struct {
|
||||
router *router.Router
|
||||
shutdown chan os.Signal
|
||||
omsetScheduler *service.OmsetMilestoneScheduler
|
||||
walletRecon *service.WalletReconciliationJob
|
||||
}
|
||||
|
||||
func NewApp(db *gorm.DB, redisClient *redis.Client) *App {
|
||||
@@ -53,6 +54,13 @@ func (a *App) Initialize(cfg *config.Config) error {
|
||||
processors.notificationProcessor,
|
||||
)
|
||||
|
||||
// Checks that wallet balances, ledger and lots agree (docs/prd-point-coin.md §7.5)
|
||||
a.walletRecon = service.NewWalletReconciliationJob(
|
||||
repository.NewWalletReconciliationRepository(a.db),
|
||||
repos.userRepo,
|
||||
processors.notificationProcessor,
|
||||
)
|
||||
|
||||
services := a.initServices(processors, repos, cfg)
|
||||
validators := a.initValidators()
|
||||
middleware := a.initMiddleware(services, cfg)
|
||||
@@ -155,6 +163,9 @@ func (a *App) Start(port string) error {
|
||||
if a.omsetScheduler != nil {
|
||||
a.omsetScheduler.Start(5 * time.Minute)
|
||||
}
|
||||
if a.walletRecon != nil {
|
||||
a.walletRecon.Start(6 * time.Hour)
|
||||
}
|
||||
|
||||
engine := a.router.Init()
|
||||
|
||||
@@ -194,6 +205,9 @@ func (a *App) Shutdown() {
|
||||
if a.omsetScheduler != nil {
|
||||
a.omsetScheduler.Stop()
|
||||
}
|
||||
if a.walletRecon != nil {
|
||||
a.walletRecon.Stop()
|
||||
}
|
||||
close(a.shutdown)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user