package payment import ( "time" "cloud.o-forge.io/core/oc-lib/models/common/pricing" "cloud.o-forge.io/core/oc-lib/models/utils" "cloud.o-forge.io/core/oc-lib/tools" ) type PaymentStatus int const ( PAYMENT_PENDING PaymentStatus = iota PAYMENT_PROCESSING // en cours de traitement blockchain/réseau PAYMENT_COMPLETED // confirmé PAYMENT_FAILED // échoué PAYMENT_CANCELLED // annulé avant exécution PAYMENT_REFUNDED // remboursé ) func (s PaymentStatus) String() string { return [...]string{"pending", "processing", "completed", "failed", "cancelled", "refunded"}[s] } func PaymentStatusList() []PaymentStatus { return []PaymentStatus{PAYMENT_PENDING, PAYMENT_PROCESSING, PAYMENT_COMPLETED, PAYMENT_FAILED, PAYMENT_CANCELLED, PAYMENT_REFUNDED} } type PaymentMethod int const ( METHOD_BLOCKCHAIN PaymentMethod = iota METHOD_CREDIT_CARD METHOD_BANK_TRANSFER METHOD_CRYPTO METHOD_INTERNAL_CREDIT // crédit interne à la plateforme ) func (m PaymentMethod) String() string { return [...]string{"blockchain", "credit_card", "bank_transfer", "crypto", "internal_credit"}[m] } func PaymentMethodList() []PaymentMethod { return []PaymentMethod{METHOD_BLOCKCHAIN, METHOD_CREDIT_CARD, METHOD_BANK_TRANSFER, METHOD_CRYPTO, METHOD_INTERNAL_CREDIT} } // Payment représente une transaction de paiement — instantanée, mensuelle ou annuelle. type Payment struct { utils.AbstractObject BillID string `json:"bill_id,omitempty" bson:"bill_id,omitempty"` InvoiceID string `json:"invoice_id,omitempty" bson:"invoice_id,omitempty"` SubscriptionID string `json:"subscription_id,omitempty" bson:"subscription_id,omitempty"` PayerPeerID string `json:"payer_peer_id,omitempty" bson:"payer_peer_id,omitempty"` RecipientPeerID string `json:"recipient_peer_id,omitempty" bson:"recipient_peer_id,omitempty"` Amount float64 `json:"amount" bson:"amount"` Currency string `json:"currency" bson:"currency" default:"EUR"` Status PaymentStatus `json:"status" bson:"status"` Method PaymentMethod `json:"method" bson:"method"` PaymentType pricing.PaymentType `json:"payment_type" bson:"payment_type"` // PAY_ONCE, PAY_EVERY_MONTH, PAY_EVERY_YEAR TransactionID string `json:"transaction_id,omitempty" bson:"transaction_id,omitempty"` WalletFrom string `json:"wallet_from,omitempty" bson:"wallet_from,omitempty"` WalletTo string `json:"wallet_to,omitempty" bson:"wallet_to,omitempty"` ScheduledAt *time.Time `json:"scheduled_at,omitempty" bson:"scheduled_at,omitempty"` ProcessedAt *time.Time `json:"processed_at,omitempty" bson:"processed_at,omitempty"` FailureReason string `json:"failure_reason,omitempty" bson:"failure_reason,omitempty"` Metadata map[string]string `json:"metadata,omitempty" bson:"metadata,omitempty"` } // NewInstantPayment crée un paiement immédiat (PAY_ONCE). func NewInstantPayment(billID, payerPeerID, recipientPeerID string, amount float64, currency string, method PaymentMethod) *Payment { return &Payment{ BillID: billID, PayerPeerID: payerPeerID, RecipientPeerID: recipientPeerID, Amount: amount, Currency: currency, Status: PAYMENT_PENDING, Method: method, PaymentType: pricing.PAY_ONCE, } } // NewScheduledPayment crée un paiement programmé (mensuel ou annuel). func NewScheduledPayment(subscriptionID, payerPeerID, recipientPeerID string, amount float64, currency string, method PaymentMethod, paymentType pricing.PaymentType, scheduledAt time.Time) *Payment { return &Payment{ SubscriptionID: subscriptionID, PayerPeerID: payerPeerID, RecipientPeerID: recipientPeerID, Amount: amount, Currency: currency, Status: PAYMENT_PENDING, Method: method, PaymentType: paymentType, ScheduledAt: &scheduledAt, } } // Complete marque le paiement comme confirmé. func (p *Payment) Complete(transactionID string) { now := time.Now().UTC() p.Status = PAYMENT_COMPLETED p.TransactionID = transactionID p.ProcessedAt = &now } // Fail marque le paiement comme échoué. func (p *Payment) Fail(reason string) { now := time.Now().UTC() p.Status = PAYMENT_FAILED p.FailureReason = reason p.ProcessedAt = &now } // Cancel annule le paiement s'il est encore en attente. func (p *Payment) Cancel() bool { if p.Status != PAYMENT_PENDING { return false } p.Status = PAYMENT_CANCELLED return true } // IsRefundable indique si le paiement peut faire l'objet d'un remboursement. func (p *Payment) IsRefundable() bool { return p.Status == PAYMENT_COMPLETED } func (p *Payment) GetAccessor(request *tools.APIRequest) utils.Accessor { return NewAccessor(request) } func (p *Payment) StoreDraftDefault() { p.IsDraft = true } func (p *Payment) CanUpdate(set utils.DBObject) (bool, utils.DBObject) { incoming := set.(*Payment) if !p.IsDraft && p.Status != incoming.Status { return true, &Payment{ Status: incoming.Status, TransactionID: incoming.TransactionID, FailureReason: incoming.FailureReason, } } return p.IsDraft, set } func (p *Payment) CanDelete() bool { return p.IsDraft || p.Status == PAYMENT_PENDING }