103 lines
3.4 KiB
Go
103 lines
3.4 KiB
Go
package plan
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/tech/sendico/payments/storage/model"
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
"github.com/tech/sendico/pkg/mlogger"
|
|
"github.com/tech/sendico/pkg/mutil/mzap"
|
|
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type defaultBuilder struct {
|
|
logger mlogger.Logger
|
|
}
|
|
|
|
func newDefaultBuilder(logger mlogger.Logger) *defaultBuilder {
|
|
return &defaultBuilder{
|
|
logger: logger.Named("plan_builder"),
|
|
}
|
|
}
|
|
|
|
func (b *defaultBuilder) Build(ctx context.Context, payment *model.Payment, quote *sharedv1.PaymentQuote, routes RouteStore, templates PlanTemplateStore, gateways GatewayRegistry) (*model.PaymentPlan, error) {
|
|
if payment == nil {
|
|
return nil, merrors.InvalidArgument("plan builder: payment is required")
|
|
}
|
|
if routes == nil {
|
|
return nil, merrors.InvalidArgument("plan builder: routes store is required")
|
|
}
|
|
if templates == nil {
|
|
return nil, merrors.InvalidArgument("plan builder: plan templates store is required")
|
|
}
|
|
|
|
logger := b.logger.With(
|
|
zap.String("payment_ref", payment.PaymentRef),
|
|
zap.String("payment_kind", string(payment.Intent.Kind)),
|
|
)
|
|
logger.Debug("Building payment plan")
|
|
|
|
intent := payment.Intent
|
|
if intent.Kind == model.PaymentKindFXConversion {
|
|
logger.Debug("Building fx conversion plan")
|
|
plan, err := buildFXConversionPlan(payment)
|
|
if err != nil {
|
|
logger.Warn("Failed to build fx conversion plan", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
logger.Info("Fx conversion plan built", zap.Int("steps", len(plan.Steps)))
|
|
return plan, nil
|
|
}
|
|
|
|
sourceRail, sourceNetwork, err := railFromEndpoint(intent.Source, intent.Attributes, true)
|
|
if err != nil {
|
|
logger.Warn("Failed to resolve source rail", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
destRail, destNetwork, err := railFromEndpoint(intent.Destination, intent.Attributes, false)
|
|
if err != nil {
|
|
logger.Warn("Failed to resolve destination rail", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
logger = logger.With(
|
|
zap.String("source_rail", string(sourceRail)),
|
|
zap.String("dest_rail", string(destRail)),
|
|
zap.String("source_network", sourceNetwork),
|
|
zap.String("dest_network", destNetwork),
|
|
)
|
|
|
|
if sourceRail == model.RailUnspecified || destRail == model.RailUnspecified {
|
|
logger.Warn("Source and destination rails are required")
|
|
return nil, merrors.InvalidArgument("plan builder: source and destination rails are required")
|
|
}
|
|
if sourceRail == destRail && sourceRail != model.RailLedger {
|
|
logger.Warn("Unsupported same-rail payment")
|
|
return nil, merrors.InvalidArgument("plan builder: unsupported same-rail payment")
|
|
}
|
|
|
|
network, err := resolveRouteNetwork(intent.Attributes, sourceNetwork, destNetwork)
|
|
if err != nil {
|
|
logger.Warn("Failed to resolve route network", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
logger = logger.With(zap.String("network", network))
|
|
|
|
route, err := selectRoute(ctx, routes, sourceRail, destRail, network)
|
|
if err != nil {
|
|
logger.Warn("Failed to select route", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
logger.Debug("Route selected", mzap.StorableRef(route))
|
|
|
|
template, err := selectPlanTemplate(ctx, logger, templates, sourceRail, destRail, network)
|
|
if err != nil {
|
|
logger.Warn("Failed to select plan template", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
logger.Debug("Plan template selected", mzap.StorableRef(template))
|
|
|
|
return b.buildPlanFromTemplate(ctx, payment, quote, template, sourceRail, destRail, sourceNetwork, destNetwork, gateways)
|
|
}
|